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 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556
|
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; $Id: ldlinux.asm,v 1.100 2001/12/10 09:03:27 hpa Exp $
3 ; ****************************************************************************
4 ;
5 ; ldlinux.asm
6 ;
7 ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
8 ; functionality is good to have for installation floppies, where it may
9 ; be hard to find a functional Linux system to run LILO off.
10 ;
11 ; This program allows manipulation of the disk to take place entirely
12 ; from MS-LOSS, and can be especially useful in conjunction with the
13 ; umsdos filesystem.
14 ;
15 ; This file is loaded in stages; first the boot sector at offset 7C00h,
16 ; then the first sector (cluster, really, but we can only assume 1 sector)
17 ; of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h.
18 ;
19 ; Copyright (C) 1994-2002 H. Peter Anvin
20 ;
21 ; This program is free software; you can redistribute it and/or modify
22 ; it under the terms of the GNU General Public License as published by
23 ; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
24 ; USA; either version 2 of the License, or (at your option) any later
25 ; version; incorporated herein by reference.
26 ;
27 ; ****************************************************************************
28
29 ;
30 ; Some semi-configurable constants... change on your own risk. Most are imposed
31 ; by the kernel.
32 ;
33 max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit
34 retry_count equ 6 ; How patient are we with the disk?
35 HIGHMEM_MAX equ 037FFFFFFh ; DEFAULT highest address for an initrd
36 DEFAULT_BAUD equ 9600 ; Default baud rate for serial port
37 BAUD_DIVISOR equ 115200 ; Serial port parameter
38 ;
39 ; Should be updated with every release to avoid bootsector/SYS file mismatch
40 ;
41 %define version_str VERSION ; Must be 4 characters long!
42 %define date DATE_STR ; Defined from the Makefile
43 %define year '2002'
44 ;
45 ; Debgging stuff
46 ;
47 ; %define debug 1 ; Uncomment to enable debugging
48 ;
49 ; ID for SYSLINUX (reported to kernel)
50 ;
51 syslinux_id equ 031h ; SYSLINUX (3) version 1.x (1)
52 ;
53 ; Segments used by Linux
54 ;
55 ; Note: the real_mode_seg is supposed to be 9000h, but some device drivers
56 ; hog some of high memory. Therefore, we load it at 7000:0000h and copy
57 ; it before starting the Linux kernel.
58 ;
59 real_mode_seg equ 7000h
60 fake_setup_seg equ real_mode_seg+020h
61
62 struc real_mode_seg_t
63 00000000 <res 00000020> resb 20h-($-$$) ; org 20h
64 00000020 <res 00000002> kern_cmd_magic resw 1 ; 0020 Magic # for command line
65 00000022 <res 00000002> kern_cmd_offset resw 1 ; 0022 Offset for kernel command line
66 00000024 <res 000001CD> resb 497-($-$$) ; org 497d
67 000001F1 <res 00000001> bs_setupsecs resb 1 ; 01F1 Sectors for setup code (0 -> 4)
68 000001F2 <res 00000002> bs_rootflags resw 1 ; 01F2 Root readonly flag
69 000001F4 <res 00000002> bs_syssize resw 1 ; 01F4
70 000001F6 <res 00000002> bs_swapdev resw 1 ; 01F6 Swap device (obsolete)
71 000001F8 <res 00000002> bs_ramsize resw 1 ; 01F8 Ramdisk flags, formerly ramdisk size
72 000001FA <res 00000002> bs_vidmode resw 1 ; 01FA Video mode
73 000001FC <res 00000002> bs_rootdev resw 1 ; 01FC Root device
74 000001FE <res 00000002> bs_bootsign resw 1 ; 01FE Boot sector signature (0AA55h)
75 00000200 <res 00000001> su_jump resb 1 ; 0200 0EBh
76 00000201 <res 00000001> su_jump2 resb 1 ; 0201 Size of following header
77 00000202 <res 00000004> su_header resd 1 ; 0202 New setup code: header
78 00000206 <res 00000002> su_version resw 1 ; 0206 See linux/arch/i386/boot/setup.S
79 00000208 <res 00000002> su_switch resw 1 ; 0208
80 0000020A <res 00000002> su_setupseg resw 1 ; 020A
81 0000020C <res 00000002> su_startsys resw 1 ; 020C
82 0000020E <res 00000002> su_kver resw 1 ; 020E Kernel version pointer
83 00000210 <res 00000001> su_loader resb 1 ; 0210 Loader ID
84 00000211 <res 00000001> su_loadflags resb 1 ; 0211 Load high flag
85 00000212 <res 00000002> su_movesize resw 1 ; 0212
86 00000214 <res 00000004> su_code32start resd 1 ; 0214 Start of code loaded high
87 00000218 <res 00000004> su_ramdiskat resd 1 ; 0218 Start of initial ramdisk
88 su_ramdisklen equ $ ; Length of initial ramdisk
89 0000021C <res 00000002> su_ramdisklen1 resw 1 ; 021C
90 0000021E <res 00000002> su_ramdisklen2 resw 1 ; 021E
91 00000220 <res 00000002> su_bsklugeoffs resw 1 ; 0220
92 00000222 <res 00000002> su_bsklugeseg resw 1 ; 0222
93 00000224 <res 00000002> su_heapend resw 1 ; 0224
94 00000226 <res 00000002> su_pad1 resw 1 ; 0226
95 00000228 <res 00000004> su_cmd_line_ptr resd 1 ; 0228
96 0000022C <res 00000004> su_ramdisk_max resd 1 ; 022C
97 00000230 <res 00008DC4> resb (9000h-12)-($-$$) ; The setup is up to 32K long
98 linux_stack equ $ ; 8FF4
99 linux_fdctab equ $
100 00008FF4 <res 0000000C> resb 9000h-($-$$)
101 cmd_line_here equ $ ; 9000 Should be out of the way
102 endstruc
103
104 ;
105 ; Kernel command line signature
106 ;
107 CMD_MAGIC equ 0A33Fh ; Command line magic
108
109 ;
110 ; Magic number of su_header field
111 ;
112 HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex)
113
114 ;
115 ; Flags for the su_loadflags field
116 ;
117 LOAD_HIGH equ 01h ; Large kernel, load high
118 CAN_USE_HEAP equ 80h ; Boot loader reports heap size
119
120 ;
121 ; The following structure is used for "virtual kernels"; i.e. LILO-style
122 ; option labels. The options we permit here are `kernel' and `append
123 ; Since there is no room in the bottom 64K for all of these, we
124 ; stick them at vk_seg:0000 and copy them down before we need them.
125 ;
126 ; Note: this structure can be added to, but it must
127 ;
128 %define vk_power 7 ; log2(max number of vkernels)
129 %define max_vk (1 << vk_power) ; Maximum number of vkernels
130 %define vk_shift (16-vk_power) ; Number of bits to shift
131 %define vk_size (1 << vk_shift) ; Size of a vkernel buffer
132
133 struc vkernel
134 00000000 <res 0000000B> vk_vname: resb 11 ; Virtual name **MUST BE FIRST!**
135 0000000B <res 0000000B> vk_rname: resb 11 ; Real name
136 00000016 <res 00000002> vk_appendlen: resw 1
137 alignb 4
138 00000018 <res 00000100> vk_append: resb max_cmd_len+1 ; Command line
139 alignb 4
140 vk_end: equ $ ; Should be <= vk_size
141 endstruc
142
143 %if (vk_end > vk_size) || (vk_size*max_vk > 65536)
144 %error "Too many vkernels defined, reduce vk_power"
145 %endif
146
147 ;
148 ; Segment assignments in the bottom 640K
149 ; Stick to the low 512K in case we're using something like M-systems flash
150 ; which load a driver into low RAM (evil!!)
151 ;
152 ; 0000h - main code/data segment (and BIOS segment)
153 ; 7000h - real_mode_seg
154 ;
155 fat_seg equ 5000h ; 128K area for FAT (2x64K)
156 vk_seg equ 4000h ; Virtual kernels
157 xfer_buf_seg equ 3000h ; Bounce buffer for I/O to high mem
158 comboot_seg equ 2000h ; COMBOOT image loading zone
159
160 ;
161 ; For our convenience: define macros for jump-over-unconditinal jumps
162 ;
163 %macro jmpz 1
164 jnz %%skip
165 jmp %1
166 %%skip:
167 %endmacro
168
169 %macro jmpnz 1
170 jz %%skip
171 jmp %1
172 %%skip:
173 %endmacro
174
175 %macro jmpe 1
176 jne %%skip
177 jmp %1
178 %%skip:
179 %endmacro
180
181 %macro jmpne 1
182 je %%skip
183 jmp %1
184 %%skip:
185 %endmacro
186
187 %macro jmpc 1
188 jnc %%skip
189 jmp %1
190 %%skip:
191 %endmacro
192
193 %macro jmpnc 1
194 jc %%skip
195 jmp %1
196 %%skip:
197 %endmacro
198
199 %macro jmpb 1
200 jnb %%skip
201 jmp %1
202 %%skip:
203 %endmacro
204
205 %macro jmpnb 1
206 jb %%skip
207 jmp %1
208 %%skip:
209 %endmacro
210
211 ;
212 ; Macros similar to res[bwd], but which works in the code segment (after
213 ; section .text)
214 ;
215 %macro zb 1
216 times %1 db 0
217 %endmacro
218
219 %macro zw 1
220 times %1 dw 0
221 %endmacro
222
223 %macro zd 1
224 times %1 dd 0
225 %endmacro
226
227 ; ---------------------------------------------------------------------------
228 ; BEGIN THE BIOS/CODE/DATA SEGMENT
229 ; ---------------------------------------------------------------------------
230 absolute 4*1Eh ; In the interrupt table
231 fdctab equ $
232 00000078 <res 00000002> fdctab1 resw 1
233 0000007A <res 00000002> fdctab2 resw 1
234
235 absolute 0400h
236 00000400 <res 00000008> serial_base resw 4 ; Base addresses for 4 serial ports
237
238 absolute 0484h
239 00000484 <res 00000001> BIOS_vidrows resb 1 ; Number of screen rows
240
241 ;
242 ; Memory below this point is reserved for the BIOS and the MBR
243 ;
244 absolute 1000h
245 trackbuf equ $ ; Track buffer goes here
246 trackbufsize equ 16384 ; Safe size of track buffer
247 ; trackbuf ends at 5000h
248
249
250 ;
251 ; Constants for the xfer_buf_seg
252 ;
253 ; The xfer_buf_seg is also used to store message file buffers. We
254 ; need two trackbuffers (text and graphics), plus a work buffer
255 ; for the graphics decompressor.
256 ;
257 xbs_textbuf equ 0 ; Also hard-coded, do not change
258 xbs_vgabuf equ trackbufsize
259 xbs_vgatmpbuf equ 2*trackbufsize
260
261
262 absolute 5000h ; Here we keep our BSS stuff
263 00005000 <res 00000200> VKernelBuf: resb vk_size ; "Current" vkernel
264 alignb 4
265 00005200 <res 00000100> AppendBuf resb max_cmd_len+1 ; append=
266 00005300 <res 00000100> KbdMap resb 256 ; Keyboard map
267 00005400 <res 000000A0> FKeyName resb 10*16 ; File names for F-key help
268 000054A0 <res 0000000F> NumBuf resb 15 ; Buffer to load number
269 000054AF <res 00000001> NumBufEnd resb 1 ; Last byte in NumBuf
270 alignb 4
271 000054B0 <res 00000010> PartInfo resb 16 ; Partition table entry
272 000054C0 <res 00000014> E820Buf resd 5 ; INT 15:E820 data buffer
273 000054D4 <res 00000004> InitRDat resd 1 ; Load address (linear) for initrd
274 000054D8 <res 00000004> HiLoadAddr resd 1 ; Address pointer for high load loop
275 000054DC <res 00000004> HighMemSize resd 1 ; End of memory pointer (bytes)
276 000054E0 <res 00000004> RamdiskMax resd 1 ; Highest address for a ramdisk
277 000054E4 <res 00000004> KernelSize resd 1 ; Size of kernel (bytes)
278 000054E8 <res 0000000C> KernelName resb 12 ; Mangled name for kernel
279 ; (note the spare byte after!)
280 RootDir equ $ ; Location of root directory
281 000054F4 <res 00000002> RootDir1 resw 1
282 000054F6 <res 00000002> RootDir2 resw 1
283 DataArea equ $ ; Location of data area
284 000054F8 <res 00000002> DataArea1 resw 1
285 000054FA <res 00000002> DataArea2 resw 1
286 FBytes equ $ ; Used by open/getc
287 000054FC <res 00000002> FBytes1 resw 1
288 000054FE <res 00000002> FBytes2 resw 1
289 00005500 <res 00000002> RootDirSize resw 1 ; Root dir size in sectors
290 00005502 <res 00000002> DirScanCtr resw 1 ; Used while searching directory
291 00005504 <res 00000002> DirBlocksLeft resw 1 ; Ditto
292 00005506 <res 00000002> EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31
293 00005508 <res 00000002> RunLinClust resw 1 ; Cluster # for LDLINUX.SYS
294 0000550A <res 00000002> ClustSize resw 1 ; Bytes/cluster
295 0000550C <res 00000002> SecPerClust resw 1 ; Same as bsSecPerClust, but a word
296 0000550E <res 00000002> NextCluster resw 1 ; Pointer to "nextcluster" routine
297 00005510 <res 00000002> BufSafe resw 1 ; Clusters we can load into trackbuf
298 00005512 <res 00000002> BufSafeSec resw 1 ; = how many sectors?
299 00005514 <res 00000002> BufSafeBytes resw 1 ; = how many bytes?
300 00005516 <res 00000002> EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytes
301 00005518 <res 00000002> KernelClust resw 1 ; Kernel size in clusters
302 0000551A <res 00000002> InitRDClust resw 1 ; Ramdisk size in clusters
303 0000551C <res 00000002> ClustPerMoby resw 1 ; Clusters per 64K
304 0000551E <res 00000002> FClust resw 1 ; Number of clusters in open/getc file
305 00005520 <res 00000002> FNextClust resw 1 ; Pointer to next cluster in d:o
306 00005522 <res 00000002> FPtr resw 1 ; Pointer to next char in buffer
307 00005524 <res 00000002> CmdOptPtr resw 1 ; Pointer to first option on cmd line
308 00005526 <res 00000002> KernelCNameLen resw 1 ; Length of unmangled kernel name
309 00005528 <res 00000002> InitRDCNameLen resw 1 ; Length of unmangled initrd name
310 0000552A <res 00000002> NextCharJump resw 1 ; Routine to interpret next print char
311 0000552C <res 00000002> SetupSecs resw 1 ; Number of setup sectors
312 0000552E <res 00000002> SavedSP resw 1 ; Our SP while running a COMBOOT image
313 00005530 <res 00000002> A20Test resw 1 ; Counter for testing status of A20
314 00005532 <res 00000002> CmdLineLen resw 1 ; Length of command line including null
315 00005534 <res 00000002> GraphXSize resw 1 ; Width of splash screen file
316 00005536 <res 00000002> VGAPos resw 1 ; Pointer into VGA memory
317 00005538 <res 00000002> VGACluster resw 1 ; Cluster pointer for VGA image file
318 0000553A <res 00000002> VGAFilePtr resw 1 ; Pointer into VGAFileBuf
319 TextAttrBX equ $
320 0000553C <res 00000001> TextAttribute resb 1 ; Text attribute for message file
321 0000553D <res 00000001> TextPage resb 1 ; Active display page
322 CursorDX equ $
323 0000553E <res 00000001> CursorCol resb 1 ; Cursor column for message file
324 0000553F <res 00000001> CursorRow resb 1 ; Cursor row for message file
325 ScreenSize equ $
326 00005540 <res 00000001> VidCols resb 1 ; Columns on screen-1
327 00005541 <res 00000001> VidRows resb 1 ; Rows on screen-1
328 FlowControl equ $
329 00005542 <res 00000001> FlowOutput resb 1 ; Outputs to assert for serial flow
330 00005543 <res 00000001> FlowInput resb 1 ; Input bits for serial flow
331 00005544 <res 00000001> FlowIgnore resb 1 ; Ignore input unless these bits set
332 00005545 <res 00000001> RetryCount resb 1 ; Used for disk access retries
333 00005546 <res 00000001> KbdFlags resb 1 ; Check for keyboard escapes
334 00005547 <res 00000001> LoadFlags resb 1 ; Loadflags from kernel
335 00005548 <res 00000001> A20Tries resb 1 ; Times until giving up on A20
336 00005549 <res 00000001> FuncFlag resb 1 ; Escape sequences received from keyboard
337 0000554A <res 00000001> DisplayMask resb 1 ; Display modes mask
338 0000554B <res 0000000B> MNameBuf resb 11 ; Generic mangled file name buffer
339 00005556 <res 0000000B> InitRD resb 11 ; initrd= mangled name
340 00005561 <res 0000000D> KernelCName resb 13 ; Unmangled kernel name
341 0000556E <res 0000000D> InitRDCName resb 13 ; Unmangled initrd name
342 0000557B <res 00000011> TextColorReg resb 17 ; VGA color registers for text mode
343 0000558C <res 0000000D> VGAFileBuf resb 13 ; Unmangled VGA image name
344 VGAFileBufEnd equ $
345 00005599 <res 0000000B> VGAFileMBuf resb 11 ; Mangled VGA image name
346
347 section .text
348 org 7C00h
349 StackBuf equ $ ; Start the stack here (grow down - 4K)
350
351 ;
352 ; Primary entry point. Tempting as though it may be, we can't put the
353 ; initial "cli" here; the jmp opcode in the first byte is part of the
354 ; "magic number" (using the term very loosely) for the DOS superblock.
355 ;
356 bootsec equ $
357 00000000 EB3C jmp short start ; 2 bytes
358 00000002 90 nop ; 1 byte
359 ;
360 ; "Superblock" follows -- it's in the boot sector, so it's already
361 ; loaded and ready for us
362 ;
363 00000003 5359534C494E5558 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
364 superblock equ $
365 bsBytesPerSec zw 1
366 <1> bsBytesPerSec :
367 0000000B 0000 <1> times %1 dw 0
368 bsSecPerClust zb 1
369 <1> bsSecPerClust :
370 0000000D 00 <1> times %1 db 0
371 bsResSectors zw 1
372 <1> bsResSectors :
373 0000000E 0000 <1> times %1 dw 0
374 bsFATs zb 1
375 <1> bsFATs :
376 00000010 00 <1> times %1 db 0
377 bsRootDirEnts zw 1
378 <1> bsRootDirEnts :
379 00000011 0000 <1> times %1 dw 0
380 bsSectors zw 1
381 <1> bsSectors :
382 00000013 0000 <1> times %1 dw 0
383 bsMedia zb 1
384 <1> bsMedia :
385 00000015 00 <1> times %1 db 0
386 bsFATsecs zw 1
387 <1> bsFATsecs :
388 00000016 0000 <1> times %1 dw 0
389 bsSecPerTrack zw 1
390 <1> bsSecPerTrack :
391 00000018 0000 <1> times %1 dw 0
392 bsHeads zw 1
393 <1> bsHeads :
394 0000001A 0000 <1> times %1 dw 0
395 bsHiddenSecs equ $
396 bsHidden1 zw 1
397 <1> bsHidden1 :
398 0000001C 0000 <1> times %1 dw 0
399 bsHidden2 zw 1
400 <1> bsHidden2 :
401 0000001E 0000 <1> times %1 dw 0
402 bsHugeSectors equ $
403 bsHugeSec1 zw 1
404 <1> bsHugeSec1 :
405 00000020 0000 <1> times %1 dw 0
406 bsHugeSec2 zw 1
407 <1> bsHugeSec2 :
408 00000022 0000 <1> times %1 dw 0
409 bsDriveNumber zb 1
410 <1> bsDriveNumber :
411 00000024 00 <1> times %1 db 0
412 bsReserved1 zb 1
413 <1> bsReserved1 :
414 00000025 00 <1> times %1 db 0
415 bsBootSignature zb 1 ; 29h if the following fields exist
416 <1> bsBootSignature :
417 00000026 00 <1> times %1 db 0
418 bsVolumeID zd 1
419 <1> bsVolumeID :
420 00000027 00000000 <1> times %1 dd 0
421 bsVolumeLabel zb 11
422 <1> bsVolumeLabel :
423 0000002B 00<rept> <1> times %1 db 0
424 bsFileSysType zb 8 ; Must be FAT12 for this version
425 <1> bsFileSysType :
426 00000036 00<rept> <1> times %1 db 0
427 superblock_len equ $-superblock
428 ;
429 ; Note we don't check the constraints above now; we did that at install
430 ; time (we hope!)
431 ;
432
433 ;floppy_table equ $ ; No sense in wasting memory, overwrite start
434
435 start:
436 0000003E FA cli ; No interrupts yet, please
437 0000003F FC cld ; Copy upwards
438 ;
439 ; Set up the stack
440 ;
441 00000040 31C9 xor cx,cx
442 00000042 8ED1 mov ss,cx
443 00000044 BC[0000] mov sp,StackBuf ; Just below BSS
444 00000047 8EC1 mov es,cx
445 ;
446 ; DS:SI may contain a partition table entry. Preserve it for us.
447 ;
448 00000049 B108 mov cl,8 ; Save partition info (CH == 0)
449 0000004B BFB054 mov di,PartInfo
450 0000004E F3A5 rep movsw
451 ;
452 ; Now sautee the BIOS floppy info block to that it will support decent-
453 ; size transfers; the floppy block is 11 bytes and is stored in the
454 ; INT 1Eh vector (brilliant waste of resources, eh?)
455 ;
456 ; Of course, if BIOSes had been properly programmed, we wouldn't have
457 ; had to waste precious boot sector space with this code.
458 ;
459 ; This code no longer fits. Hope that noone really needs it anymore.
460 ; (If so, it needs serious updating.) In fact, some indications is that
461 ; this code does more harm than good with all the new kinds of drives and
462 ; media.
463 ;
464 %ifdef SUPPORT_REALLY_BROKEN_BIOSES
465 lds si,[ss:fdctab] ; DS:SI -> original
466 push ds ; Save on stack in case
467 push si ; we have to bail
468 push bx
469 mov cx,6 ; 12 bytes
470 mov di,floppy_table
471 push di
472 cld
473 rep movsw ; Faster to move words
474 pop di
475 mov ds,ax ; Now we can point DS to here, too
476 mov cl,[bsSecPerTrack] ; Patch the sector count
477 mov [di+4],cl
478 mov [fdctab+2],ax ; Segment 0
479 mov [fdctab],di ; offset floppy_block
480 %else
481 00000050 8ED9 mov ds,cx ; CX == 0
482 %endif
483 ;
484 ; Ready to enable interrupts, captain
485 ;
486 00000052 FB sti
487 ;
488 ; The drive number and possibly partition information was passed to us
489 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
490 ; trust that rather than what the superblock contains.
491 ;
492 ; Would it be better to zero out bsHidden if we don't have a partition table?
493 ;
494 ; Note: di points to beyond the end of PartInfo
495 ;
496 00000053 8816[2400] mov [bsDriveNumber],dl
497 00000057 F6C280 test dl,80h ; If floppy disk (00-7F), assume no
498 0000005A 7428 jz not_harddisk ; partition table
499 0000005C F645F07F test byte [di-16],7Fh ; Sanity check: "active flag" should
500 00000060 750A jnz no_partition ; be 00 or 80
501 00000062 8D75F8 lea si,[di-8] ; Partition offset (dword)
502 00000065 BF[1C00] mov di,bsHidden1
503 00000068 B102 mov cl,2 ; CH == 0
504 0000006A F3A5 rep movsw
505 no_partition:
506 ;
507 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
508 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
509 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
510 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
511 ;
512 ; DL == drive # still
513 0000006C B408 mov ah,08h
514 0000006E CD13 int 13h
515 00000070 7212 jc no_driveparm
516 00000072 20E4 and ah,ah
517 00000074 750E jnz no_driveparm
518 00000076 FEC6 inc dh ; Contains # of heads - 1
519 00000078 8836[1A00] mov [bsHeads],dh
520 0000007C 81E13F00 and cx,3fh
521 00000080 890E[1800] mov [bsSecPerTrack],cx
522 no_driveparm:
523 not_harddisk:
524 ;
525 ; Now we have to do some arithmetric to figure out where things are located.
526 ; If Micro$oft had had brains they would already have done this for us,
527 ; and stored it in the superblock at format time, but here we go,
528 ; wasting precious boot sector space again...
529 ;
530 debugentrypt:
531 00000084 31C0 xor ax,ax ; INT 13:08 destroys ES
532 00000086 8EC0 mov es,ax
533 00000088 A0[1000] mov al,[bsFATs] ; Number of FATs (AH == 0)
534 0000008B F726[1600] mul word [bsFATsecs] ; Get the size of the FAT area
535 0000008F 0306[1C00] add ax,[bsHidden1] ; Add hidden sectors
536 00000093 1316[1E00] adc dx,[bsHidden2]
537 00000097 0306[0E00] add ax,[bsResSectors] ; And reserved sectors
538 0000009B 83D200 adc dx,byte 0
539
540 0000009E A3F454 mov [RootDir1],ax ; Location of root directory
541 000000A1 8916F654 mov [RootDir2],dx
542 000000A5 A3F854 mov [DataArea1],ax
543 000000A8 8916FA54 mov [DataArea2],dx
544 000000AC 50 push ax
545 000000AD 52 push dx
546
547 000000AE B82000 mov ax,32 ; Size of a directory entry
548 000000B1 F726[1100] mul word [bsRootDirEnts]
549 000000B5 8B1E[0B00] mov bx,[bsBytesPerSec]
550 000000B9 01D8 add ax,bx ; Round up, not down
551 000000BB 48 dec ax
552 000000BC F7F3 div bx ; Now we have the size of the root dir
553 000000BE A30055 mov [RootDirSize],ax
554 000000C1 A30255 mov [DirScanCtr],ax
555 000000C4 81C3E10F add bx,trackbuf-31
556 000000C8 891E0655 mov [EndofDirSec],bx ; End of a single directory sector
557
558 000000CC 0106F854 add [DataArea1],ax
559 000000D0 8316FA5400 adc word [DataArea2],byte 0
560
561 000000D5 5A pop dx ; Reload root directory starting point
562 000000D6 58 pop ax
563 ;
564 ; Now the fun begins. We have to search the root directory for
565 ; LDLINUX.SYS and load the first sector, so we have a little more
566 ; space to have fun with. Then we can go chasing through the FAT.
567 ; Joy!!
568 ;
569 000000D7 50 sd_nextsec: push ax
570 000000D8 52 push dx
571 000000D9 BB0010 mov bx,trackbuf
572 000000DC 53 push bx
573 000000DD E89100 call getonesec
574 000000E0 5E pop si
575 000000E1 803C00 sd_nextentry: cmp byte [si],0 ; Directory high water mark
576 000000E4 7429 je kaboom
577 000000E6 F6440B18 test byte [si+11],18h ; Must be a file
578 000000EA 750C jnz sd_not_file
579 000000EC BF[EF01] mov di,ldlinux_name
580 000000EF B90B00 mov cx,11
581 000000F2 56 push si
582 000000F3 F3A6 repe cmpsb
583 000000F5 5E pop si
584 000000F6 742D je found_it
585 000000F8 83C620 sd_not_file: add si,byte 32 ; Distance to next
586 000000FB 3B360655 cmp si,[EndofDirSec]
587 000000FF 72E0 jb sd_nextentry
588 00000101 5A pop dx
589 00000102 58 pop ax
590 00000103 83C001 add ax,byte 1
591 00000106 83D200 adc dx,byte 0
592 00000109 FF0E0255 dec word [DirScanCtr]
593 0000010D 75C8 jnz sd_nextsec
594 ;
595 ; kaboom: write a message and bail out.
596 ;
597 kaboom:
598 0000010F 31F6 xor si,si
599 00000111 8ED6 mov ss,si
600 00000113 BC[0000] mov sp,StackBuf ; Reset stack
601 00000116 8EDE mov ds,si ; Reset data segment
602 00000118 BE[DE01] .patch: mov si,bailmsg
603 0000011B E83900 call writestr ; Returns with AL = 0
604 0000011E 98 cbw ; AH <- 0
605 0000011F CD16 int 16h ; Wait for keypress
606 00000121 CD19 int 19h ; And try once more to boot...
607 00000123 EBFE .norge: jmp short .norge ; If int 19h returned; this is the end
608
609 ;
610 ; found_it: now we compute the location of the first sector, then
611 ; load it and JUMP (since we're almost out of space)
612 ;
613 found_it: ; Note: we actually leave two words on the stack here
614 ; (who cares?)
615 00000125 31C0 xor ax,ax
616 00000127 A0[0D00] mov al,[bsSecPerClust]
617 0000012A 89C5 mov bp,ax ; Load an entire cluster
618 0000012C 8B5C1A mov bx,[si+26] ; First cluster
619 0000012F 891E0855 mov [RunLinClust],bx ; Save for later use
620 00000133 4B dec bx ; First cluster is "cluster 2"
621 00000134 4B dec bx
622 00000135 F7E3 mul bx
623 00000137 0306F854 add ax,[DataArea1]
624 0000013B 1316FA54 adc dx,[DataArea2]
625 0000013F BB[0002] mov bx,ldlinux_sys
626 00000142 E82F00 call getlinsec
627 00000145 BE[EF01] mov si,bs_magic
628 00000148 BF[1F02] mov di,ldlinux_magic
629 0000014B B91100 mov cx,magic_len
630 0000014E F3A6 repe cmpsb ; Make sure that the bootsector
631 00000150 75BD jne kaboom ; matches LDLINUX.SYS
632 ;
633 ; Done! Jump to the entry point!
634 ;
635 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
636 ; instead of 0000:7C00 and the like. We don't want to add anything
637 ; more to the boot sector, so it is written to not assume a fixed
638 ; value in CS, but we don't want to deal with that anymore from now
639 ; on.
640 ;
641 00000152 EA[3002]0000 jmp 0:ldlinux_ent
642
643 ;
644 ;
645 ; writestr: write a null-terminated string to the console
646 ;
647 writestr:
648 00000157 AC wstr_1: lodsb
649 00000158 20C0 and al,al
650 0000015A 7414 jz return
651 0000015C B40E mov ah,0Eh ; Write to screen as TTY
652 0000015E BB0700 mov bx,0007h ; White on black, current page
653 00000161 CD10 int 10h
654 00000163 EBF2 jmp short wstr_1
655 ;
656 ; disk_error: decrement the retry count and bail if zero
657 ;
658 00000165 4E disk_error: dec si ; SI holds the disk retry counter
659 00000166 74A7 jz kaboom
660 00000168 5B pop bx ; <I>
661 00000169 59 pop cx ; <H>
662 0000016A 5A pop dx ; <G>
663 0000016B 58 pop ax ; <F> (AH = 0)
664 0000016C B001 mov al,1 ; Once we fail, only transfer 1 sector
665 0000016E EB39 jmp short disk_try_again
666
667 00000170 C3 return: ret
668
669 ;
670 ; getonesec: like getlinsec, but pre-sets the count to 1
671 ;
672 getonesec:
673 00000171 BD0100 mov bp,1
674 ; Fall through to getlinsec
675
676 ;
677 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
678 ; number in DX:AX into the buffer at ES:BX. We try to optimize
679 ; by loading up to a whole track at a time, but the user
680 ; is responsible for not crossing a 64K boundary.
681 ; (Yes, BP is weird for a count, but it was available...)
682 ;
683 ; On return, BX points to the first byte after the transferred
684 ; block.
685 ;
686 ; The "stupid patch area" gets replaced by the code
687 ; mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with
688 ; the -s option.
689 ;
690 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
691 ; that is dead from that point; this saves space. However, please keep
692 ; the order to dst,src to keep things sane.
693 ;
694 getlinsec:
695 00000174 8B36[1800] mov si,[bsSecPerTrack]
696 ;
697 ; Dividing by sectors to get (track,sector): we may have
698 ; up to 2^18 tracks, so we need to do this in two steps
699 ; to produce a 32-bit quotient.
700 ;
701 00000178 91 xchg cx,ax ; CX <- LSW of LBA
702 00000179 92 xchg ax,dx
703 0000017A 31D2 xor dx,dx ; DX:AX now == MSW of LBA
704 0000017C F7F6 div si ; Obtain MSW of track #
705 0000017E 91 xchg ax,cx ; Remainder -> MSW of new dividend
706 ; LSW of LBA -> LSW of new dividend
707 ; Quotient -> MSW of track #
708 0000017F F7F6 div si ; Obtain LSW of track #, remainder
709 00000181 87CA xchg cx,dx ; CX <- Sector index (0-based)
710 ; DX <- MSW of track #
711 00000183 F736[1A00] div word [bsHeads] ; Convert track to head/cyl
712 ;
713 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
714 ; BP = sectors to transfer, SI = bsSecPerTrack,
715 ; ES:BX = data target
716 ;
717 00000187 56 gls_nextchunk: push si ; <A> bsSecPerTrack
718 00000188 55 push bp ; <B> Sectors to transfer
719
720 __BEGIN_STUPID_PATCH_AREA:
721 00000189 29CE sub si,cx ; Sectors left on track
722 0000018B 39F5 cmp bp,si
723 0000018D 7602 jna gls_lastchunk
724 0000018F 89F5 mov bp,si ; No more than a trackful, please!
725 __END_STUPID_PATCH_AREA:
726 gls_lastchunk:
727 00000191 50 push ax ; <C> Cylinder #
728 00000192 52 push dx ; <D> Head #
729
730 00000193 51 push cx ; <E> Sector #
731 00000194 B106 mov cl,6 ; Because IBM was STOOPID
732 00000196 D2E4 shl ah,cl ; and thought 8 bits were enough
733 ; then thought 10 bits were enough...
734 00000198 59 pop cx ; <E> Sector #
735 00000199 51 push cx ; <E> Sector #
736 0000019A 41 inc cx ; Sector numbers are 1-based
737 0000019B 08E1 or cl,ah
738 0000019D 88C5 mov ch,al
739 0000019F 88D6 mov dh,dl
740 000001A1 8A16[2400] mov dl,[bsDriveNumber]
741 000001A5 95 xchg ax,bp ; Sector to transfer count
742 ; (xchg shorter than mov)
743 000001A6 BE0600 mov si,retry_count ; # of times to retry a disk access
744 ;
745 ; Do the disk transfer... save the registers in case we fail :(
746 ;
747 disk_try_again:
748 000001A9 50 push ax ; <F> Number of sectors we're transferring
749 000001AA B402 mov ah,02h ; READ DISK
750 000001AC 52 push dx ; <G>
751 000001AD 51 push cx ; <H>
752 000001AE 53 push bx ; <I>
753 000001AF 56 push si ; <J>
754 000001B0 CD13 int 13h
755 000001B2 5E pop si ; <J>
756 000001B3 72B0 jc disk_error
757 ;
758 ; Disk access successful
759 ;
760 000001B5 5B pop bx ; <I> Buffer location
761 000001B6 58 pop ax ; <H> No longer needed
762 000001B7 58 pop ax ; <G> No longer needed
763 000001B8 5F pop di ; <F> Sector transferred count
764 000001B9 59 pop cx ; <E> Sector #
765 000001BA 89F8 mov ax,di ; Reduce sector left count
766 000001BC F726[0B00] mul word [bsBytesPerSec] ; Figure out how much to advance ptr
767 000001C0 01C3 add bx,ax ; Update buffer location
768 000001C2 5A pop dx ; <D> Head #
769 000001C3 58 pop ax ; <C> Cyl #
770 000001C4 5D pop bp ; <B> Sectors left to transfer
771 000001C5 5E pop si ; <A> Number of sectors/track
772 000001C6 29FD sub bp,di ; Reduce with # of sectors just read
773 000001C8 74A6 jz return ; Done!
774 000001CA 01F9 add cx,di
775 000001CC 39F1 cmp cx,si
776 000001CE 72B7 jb gls_nextchunk
777 000001D0 42 inc dx ; Next track on cyl
778 000001D1 3B16[1A00] cmp dx,[bsHeads] ; Was this the last one?
779 000001D5 7203 jb gls_nonewcyl
780 000001D7 40 inc ax ; If so, new cylinder
781 000001D8 31D2 xor dx,dx ; First head on new cylinder
782 000001DA 29F1 gls_nonewcyl: sub cx,si ; First sector on new track
783 000001DC EBA9 jmp short gls_nextchunk
784
785 000001DE 426F6F74206661696C- bailmsg: db 'Boot failed', 0Dh, 0Ah, 0
786 000001E7 65640D0A00
787
788 bs_checkpt equ $ ; Must be <= 7DEFh
789
790 bs_checkpt_off equ ($-$$)
791 %if bs_checkpt_off > 1EFh
792 %error "Boot sector overflow"
793 %endif
794
795 zb 1EFh-($-$$)
796 000001EC 00<rept> <1> times %1 db 0
797 bs_magic equ $ ; From here to the magic_len equ
798 ; must match ldlinux_magic
799 000001EF 4C444C494E55582053- ldlinux_name: db 'LDLINUX SYS' ; Looks like this in the root dir
800 000001F8 5953
801 000001FA 73AE323C dd HEXDATE ; Hopefully unique between compiles
802
803 000001FE 55AA bootsignature dw 0AA55h
804 magic_len equ $-bs_magic
805
806 ;
807 ; ===========================================================================
808 ; End of boot sector
809 ; ===========================================================================
810 ; Start of LDLINUX.SYS
811 ; ===========================================================================
812
813 ldlinux_sys:
814
815 00000200 0D0A5359534C494E55- syslinux_banner db 0Dh, 0Ah, 'SYSLINUX ', version_str, ' ', date, ' ', 0
816 00000209 5820312E3636203230-
817 00000212 30322D30312D303120-
818 0000021B 00
819 0000021C 0D0A1A db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
820
821 0000021F 4C444C494E55582053- ldlinux_magic db 'LDLINUX SYS'
822 00000228 5953
823 0000022A 73AE323C dd HEXDATE
824 0000022E 55AA dw 0AA55h
825
826 align 4
827
828 ldlinux_ent:
829 ;
830 ; Tell the user we got this far
831 ;
832 00000230 BE[0002] mov si,syslinux_banner
833 00000233 E821FF call writestr
834 ;
835 ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS.
836 ; We can really only rely on a single sector having been loaded. Hence
837 ; we should load the FAT into RAM and start chasing pointers...
838 ;
839 00000236 BA0100 mov dx,1 ; 64K
840 00000239 31C0 xor ax,ax
841 0000023B F736[0B00] div word [bsBytesPerSec] ; sectors/64K
842 0000023F 89C6 mov si,ax
843
844 00000241 06 push es
845 00000242 BB0050 mov bx,fat_seg ; Load into fat_seg:0000
846 00000245 8EC3 mov es,bx
847
848 00000247 A1[1C00] mov ax,[bsHidden1] ; Hidden sectors
849 0000024A 8B16[1E00] mov dx,[bsHidden2]
850 0000024E 0306[0E00] add ax,[bsResSectors] ; plus reserved sectors = FAT
851 00000252 83D200 adc dx,byte 0
852 00000255 8B0E[1600] mov cx,[bsFATsecs] ; Sectors/FAT
853 fat_load_loop:
854 00000259 89CD mov bp,cx
855 0000025B 39F5 cmp bp,si
856 0000025D 7602 jna fat_load
857 0000025F 89F5 mov bp,si ; A full 64K moby
858 fat_load:
859 00000261 31DB xor bx,bx ; Offset 0 in the current ES
860 00000263 E82201 call getlinsecsr
861 00000266 29E9 sub cx,bp
862 00000268 740F jz fat_load_done ; Last moby?
863 0000026A 01E8 add ax,bp ; Advance sector count
864 0000026C 83D200 adc dx,byte 0
865 0000026F 8CC3 mov bx,es ; Next 64K moby
866 00000271 81C30010 add bx,1000h
867 00000275 8EC3 mov es,bx
868 00000277 EBE0 jmp short fat_load_loop
869 fat_load_done:
870 00000279 07 pop es
871 ;
872 ; Fine, now we have the FAT in memory. How big is a cluster, really?
873 ; Also figure out how many clusters will fit in an 8K buffer, and how
874 ; many sectors and bytes that is
875 ;
876 0000027A 8B3E[0B00] mov di,[bsBytesPerSec] ; Used a lot below
877
878 0000027E A0[0D00] mov al,[bsSecPerClust] ; We do this in the boot
879 00000281 30E4 xor ah,ah ; sector, too, but there
880 00000283 A30C55 mov [SecPerClust],ax ; wasn't space to save it
881 00000286 89C6 mov si,ax ; Also used a lot...
882 00000288 F7E7 mul di
883 0000028A A30A55 mov [ClustSize],ax ; Bytes/cluster
884 0000028D 89C3 mov bx,ax
885 0000028F B80040 mov ax,trackbufsize
886 00000292 31D2 xor dx,dx
887 00000294 F7F3 div bx
888 00000296 A31055 mov [BufSafe],ax ; # of cluster in trackbuf
889 00000299 F7260C55 mul word [SecPerClust]
890 0000029D A31255 mov [BufSafeSec],ax
891 000002A0 F7E7 mul di
892 000002A2 A31455 mov [BufSafeBytes],ax
893 000002A5 05009C add ax,getcbuf ; Size of getcbuf is the same
894 000002A8 A31655 mov [EndOfGetCBuf],ax ; as for trackbuf
895 ;
896 ; FAT12 or FAT16? This computation is fscking ridiculous...
897 ;
898 000002AB 31D2 xor dx,dx
899 000002AD 31C9 xor cx,cx
900 000002AF A1[1300] mov ax,[bsSectors]
901 000002B2 21C0 and ax,ax
902 000002B4 7507 jnz have_secs
903 000002B6 A1[2000] mov ax,[bsHugeSectors]
904 000002B9 8B16[2200] mov dx,[bsHugeSectors+2]
905 000002BD 2B06[0E00] have_secs: sub ax,[bsResSectors]
906 000002C1 83DA00 sbb dx,byte 0
907 000002C4 8A0E[1000] mov cl,[bsFATs]
908 000002C8 2B06[1600] sec_fat_loop: sub ax,[bsFATsecs]
909 000002CC 83DA00 sbb dx,byte 0
910 000002CF E2F7 loop sec_fat_loop
911 000002D1 50 push ax
912 000002D2 52 push dx
913 000002D3 A1[1100] mov ax,[bsRootDirEnts]
914 000002D6 BB2000 mov bx,32 ; Smaller than shift since we
915 000002D9 F7E3 mul bx ; need the doubleword product
916 000002DB 01F8 add ax,di
917 000002DD 83D200 adc dx,byte 0
918 000002E0 83E801 sub ax,byte 1
919 000002E3 83DA00 sbb dx,byte 0
920 000002E6 F7F7 div di
921 000002E8 89C3 mov bx,ax
922 000002EA 5A pop dx
923 000002EB 58 pop ax
924 000002EC 29D8 sub ax,bx
925 000002EE 83DA00 sbb dx,byte 0
926 000002F1 F7F6 div si
927 000002F3 3DF60F cmp ax,4086 ; Right value?
928 000002F6 B8[BF03] mov ax,nextcluster_fat16
929 000002F9 7703 ja have_fat_type
930 000002FB B8[9803] have_fat12: mov ax,nextcluster_fat12
931 000002FE A30E55 have_fat_type: mov word [NextCluster],ax
932
933 ;
934 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
935 ; cluster again, though.
936 ;
937 load_rest:
938 00000301 8B0E0A55 mov cx,[ClustSize]
939 00000305 BB[0002] mov bx,ldlinux_sys
940 00000308 01CB add bx,cx
941 0000030A 8B360855 mov si,[RunLinClust]
942 0000030E FF160E55 call [NextCluster]
943 00000312 31D2 xor dx,dx
944 00000314 B8751D mov ax,ldlinux_len-1 ; To be on the safe side
945 00000317 01C8 add ax,cx
946 00000319 F7F1 div cx ; the number of clusters
947 0000031B 48 dec ax ; We've already read one
948 0000031C 7405 jz all_read_jmp
949 0000031E 89C1 mov cx,ax
950 00000320 E80300 call getfssec
951 ;
952 ; All loaded up
953 ;
954 all_read_jmp:
955 00000323 E9B100 jmp all_read
956 ;
957 ; -----------------------------------------------------------------------------
958 ; Subroutines that have to be in the first sector
959 ; -----------------------------------------------------------------------------
960 ;
961 ; getfssec: Get multiple clusters from a file, given the starting cluster.
962 ;
963 ; This routine makes sure the subtransfers do not cross a 64K boundary,
964 ; and will correct the situation if it does, UNLESS *sectors* cross
965 ; 64K boundaries.
966 ;
967 ; ES:BX -> Buffer
968 ; SI -> Starting cluster number (2-based)
969 ; CX -> Cluster count (0FFFFh = until end of file)
970 ;
971 ; 386 check
972 getfssec:
973 00000326 31ED getfragment: xor bp,bp ; Fragment sector count
974 00000328 89F0 mov ax,si ; Get sector address
975 0000032A 48 dec ax ; Convert to 0-based
976 0000032B 48 dec ax
977 0000032C F7260C55 mul word [SecPerClust]
978 00000330 0306F854 add ax,[DataArea1]
979 00000334 1316FA54 adc dx,[DataArea2]
980 getseccnt: ; See if we can read > 1 clust
981 00000338 032E0C55 add bp,[SecPerClust]
982 0000033C 49 dec cx ; Reduce clusters left to find
983 0000033D 89F7 mov di,si ; Predict next cluster
984 0000033F 47 inc di
985 00000340 FF160E55 call [NextCluster]
986 00000344 7207 jc gfs_eof ; At EOF?
987 00000346 E304 jcxz endfragment ; Or was it the last we wanted?
988 00000348 39FE cmp si,di ; Is file continuous?
989 0000034A 74EC jz getseccnt ; Yes, we can get
990 0000034C F8 endfragment: clc ; Not at EOF
991 0000034D 9C gfs_eof: pushf ; Remember EOF or not
992 0000034E 56 push si
993 0000034F 51 push cx
994 gfs_getchunk:
995 00000350 50 push ax
996 00000351 52 push dx
997 00000352 8CC0 mov ax,es ; Check for 64K boundaries.
998 00000354 B104 mov cl,4
999 00000356 D3E0 shl ax,cl
1000 00000358 01D8 add ax,bx
1001 0000035A 31D2 xor dx,dx
1002 0000035C F7D8 neg ax
1003 0000035E 7501 jnz gfs_partseg
1004 00000360 42 inc dx ; Full 64K segment
1005 gfs_partseg:
1006 00000361 F736[0B00] div word [bsBytesPerSec] ; How many sectors fit?
1007 00000365 89EE mov si,bp
1008 00000367 29C6 sub si,ax ; Compute remaining sectors
1009 00000369 7610 jbe gfs_lastchunk
1010 0000036B 89C5 mov bp,ax
1011 0000036D 5A pop dx
1012 0000036E 58 pop ax
1013 0000036F E81600 call getlinsecsr
1014 00000372 01E8 add ax,bp
1015 00000374 83D200 adc dx,byte 0
1016 00000377 89F5 mov bp,si ; Remaining sector count
1017 00000379 EBD5 jmp short gfs_getchunk
1018 0000037B 5A gfs_lastchunk: pop dx
1019 0000037C 58 pop ax
1020 0000037D E8F4FD call getlinsec
1021 00000380 59 pop cx
1022 00000381 5E pop si
1023 00000382 9D popf
1024 00000383 E302 jcxz gfs_return ; If we hit the count limit
1025 00000385 739F jnc getfragment ; If we didn't hit EOF
1026 00000387 C3 gfs_return: ret
1027
1028 ;
1029 ; getlinsecsr: save registers, call getlinsec, restore registers
1030 ;
1031 00000388 50 getlinsecsr: push ax
1032 00000389 52 push dx
1033 0000038A 51 push cx
1034 0000038B 55 push bp
1035 0000038C 56 push si
1036 0000038D 57 push di
1037 0000038E E8E3FD call getlinsec
1038 00000391 5F pop di
1039 00000392 5E pop si
1040 00000393 5D pop bp
1041 00000394 59 pop cx
1042 00000395 5A pop dx
1043 00000396 58 pop ax
1044 00000397 C3 ret
1045
1046 ;
1047 ; nextcluster: Advance a cluster pointer in SI to the next cluster
1048 ; pointed at in the FAT tables (note: FAT12 assumed)
1049 ; Sets CF on return if end of file.
1050 ;
1051 ; The variable NextCluster gets set to the appropriate
1052 ; value here.
1053 ;
1054 nextcluster_fat12:
1055 00000398 50 push ax
1056 00000399 1E push ds
1057 0000039A B80050 mov ax,fat_seg
1058 0000039D 8ED8 mov ds,ax
1059 0000039F 89F0 mov ax,si ; Multiply by 3/2
1060 000003A1 D1E8 shr ax,1
1061 000003A3 9C pushf ; CF now set if odd
1062 000003A4 01C6 add si,ax
1063 000003A6 8B34 mov si,[si]
1064 000003A8 9D popf
1065 000003A9 7308 jnc nc_even
1066 000003AB D1EE shr si,1 ; Needed for odd only
1067 000003AD D1EE shr si,1
1068 000003AF D1EE shr si,1
1069 000003B1 D1EE shr si,1
1070 nc_even:
1071 000003B3 81E6FF0F and si,0FFFh
1072 000003B7 81FEF00F cmp si,0FF0h ; Clears CF if at end of file
1073 000003BB F5 cmc ; But we want it SET...
1074 000003BC 1F pop ds
1075 000003BD 58 pop ax
1076 000003BE C3 nc_return: ret
1077
1078 ;
1079 ; FAT16 decoding routine. Note that a 16-bit FAT can be up to 128K,
1080 ; so we have to decide if we're in the "low" or the "high" 64K-segment...
1081 ;
1082 nextcluster_fat16:
1083 000003BF 50 push ax
1084 000003C0 1E push ds
1085 000003C1 B80050 mov ax,fat_seg
1086 000003C4 D1E6 shl si,1
1087 000003C6 7303 jnc .seg0
1088 000003C8 B80060 mov ax,fat_seg+1000h
1089 000003CB 8ED8 .seg0: mov ds,ax
1090 000003CD 8B34 mov si,[si]
1091 000003CF 81FEF0FF cmp si,0FFF0h
1092 000003D3 F5 cmc
1093 000003D4 1F pop ds
1094 000003D5 58 pop ax
1095 000003D6 C3 ret
1096 ;
1097 ; Debug routine
1098 ;
1099 %ifdef debug
1100 safedumpregs:
1101 cmp word [Debug_Magic],0D00Dh
1102 jnz nc_return
1103 jmp dumpregs
1104 %endif
1105
1106 rl_checkpt equ $ ; Must be <= 8000h
1107
1108 rl_checkpt_off equ ($-$$)
1109 %if rl_checkpt_off > 400h
1110 %error "Sector 1 overflow"
1111 %endif
1112
1113 ; ----------------------------------------------------------------------------
1114 ; End of code and data that have to be in the first sector
1115 ; ----------------------------------------------------------------------------
1116
1117 all_read:
1118 ;
1119 ; Let the user (and programmer!) know we got this far. This used to be
1120 ; in Sector 1, but makes a lot more sense here.
1121 ;
1122 000003D7 BE[F318] mov si,copyright_str
1123 000003DA E87AFD call writestr
1124 ;
1125 ; Check that no moron is trying to boot Linux on a 286 or so. According
1126 ; to Intel, the way to check is to see if the high 4 bits of the FLAGS
1127 ; register are either all stuck at 1 (8086/8088) or all stuck at 0
1128 ; (286 in real mode), if not it is a 386 or higher. They didn't
1129 ; say how to check for a 186/188, so I *hope* it falls out as a 8086
1130 ; or 286 in this test.
1131 ;
1132 ; Also, provide an escape route in case it doesn't work.
1133 ;
1134 check_escapes:
1135 000003DD B402 mov ah,02h ; Check keyboard flags
1136 000003DF CD16 int 16h
1137 000003E1 A24655 mov [KbdFlags],al ; Save for boot prompt check
1138 000003E4 A804 test al,04h ; Ctrl->skip 386 check
1139 000003E6 7538 jnz skip_checks
1140 test_8086:
1141 000003E8 9C pushf ; Get flags
1142 000003E9 58 pop ax
1143 000003EA 25FF0F and ax,0FFFh ; Clear top 4 bits
1144 000003ED 50 push ax ; Load into FLAGS
1145 000003EE 9D popf
1146 000003EF 9C pushf ; And load back
1147 000003F0 58 pop ax
1148 000003F1 2500F0 and ax,0F000h ; Get top 4 bits
1149 000003F4 3D00F0 cmp ax,0F000h ; If set -> 8086/8088
1150 000003F7 740E je not_386
1151 test_286:
1152 000003F9 9C pushf ; Get flags
1153 000003FA 58 pop ax
1154 000003FB 0D00F0 or ax,0F000h ; Set top 4 bits
1155 000003FE 50 push ax
1156 000003FF 9D popf
1157 00000400 9C pushf
1158 00000401 58 pop ax
1159 00000402 2500F0 and ax,0F000h ; Get top 4 bits
1160 00000405 7509 jnz is_386 ; If not clear -> 386
1161 not_386:
1162 00000407 BE[6B19] mov si,err_not386
1163 0000040A E84AFD call writestr
1164 0000040D E9FFFC jmp kaboom
1165 is_386:
1166 ; Now we know it's a 386 or higher
1167 ;
1168 ; Now check that there is at least 512K of low (DOS) memory
1169 ;
1170 00000410 CD12 int 12h
1171 00000412 3D0002 cmp ax,512
1172 00000415 7309 jae enough_ram
1173 00000417 BE[581A] mov si,err_noram
1174 0000041A E83AFD call writestr
1175 0000041D E9EFFC jmp kaboom
1176 enough_ram:
1177 skip_checks:
1178 ;
1179 ; Check if we're 386 (as opposed to 486+); if so we need to blank out
1180 ; the WBINVD instruction
1181 ;
1182 ; We check for 486 by setting EFLAGS.AC
1183 ;
1184 00000420 669C pushfd ; Save the good flags
1185 00000422 669C pushfd
1186 00000424 6658 pop eax
1187 00000426 6689C3 mov ebx,eax
1188 00000429 663500000400 xor eax,(1 << 18) ; AC bit
1189 0000042F 6650 push eax
1190 00000431 669D popfd
1191 00000433 669C pushfd
1192 00000435 6658 pop eax
1193 00000437 669D popfd ; Restore the original flags
1194 00000439 6631D8 xor eax,ebx
1195 0000043C 7505 jnz is_486
1196 ;
1197 ; 386 - Looks like we better blot out the WBINVD instruction
1198 ;
1199 0000043E C606[0810]C3 mov byte [try_wbinvd],0c3h ; Near RET
1200 is_486:
1201
1202 ;
1203 ; Initialization that does not need to go into the any of the pre-load
1204 ; areas
1205 ;
1206 ; Now set up screen parameters
1207 00000443 E8710D call adjust_screen
1208 ;
1209 ; Now, everything is "up and running"... patch kaboom for more
1210 ; verbosity and using the full screen system
1211 ;
1212 00000446 C606[1801]E9 mov byte [kaboom.patch],0e9h ; JMP NEAR
1213 0000044B C706[1901]3313 mov word [kaboom.patch+1],kaboom2-(kaboom.patch+3)
1214
1215 ;
1216 ; Now we're all set to start with our *real* business. First load the
1217 ; configuration file (if any) and parse it.
1218 ;
1219 ; In previous versions I avoided using 32-bit registers because of a
1220 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1221 ; random. I figure, though, that if there are any of those still left
1222 ; they probably won't be trying to install Linux on them...
1223 ;
1224 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1225 ; to take'm out. In fact, we may want to put them back if we're going
1226 ; to boot ELKS at some point.
1227 ;
1228 00000451 BE[7C1D] mov si,linuxauto_cmd ; Default command: "linux auto"
1229 00000454 BF[951E] mov di,default_cmd
1230 00000457 B90B00 mov cx,linuxauto_len
1231 0000045A F3A4 rep movsb
1232
1233 0000045C BF0053 mov di,KbdMap ; Default keymap 1:1
1234 0000045F 30C0 xor al,al
1235 00000461 B90001 mov cx,256
1236 00000464 AA mkkeymap: stosb
1237 00000465 FEC0 inc al
1238 00000467 E2FB loop mkkeymap
1239
1240 ;
1241 ; Load configuration file
1242 ;
1243 00000469 BF[FE1C] mov di,syslinux_cfg
1244 0000046C E8EF0F call open
1245 0000046F 0F844D02 jz near no_config_file
1246 parse_config:
1247 00000473 E88410 call getkeyword
1248 00000476 0F824302 jc near end_config_file ; Config file loaded
1249 0000047A 3D6465 cmp ax,'de' ; DEfault
1250 0000047D 7449 je pc_default
1251 0000047F 3D6170 cmp ax,'ap' ; APpend
1252 00000482 744F je pc_append
1253 00000484 3D7469 cmp ax,'ti' ; TImeout
1254 00000487 0F849700 je near pc_timeout
1255 0000048B 3D7072 cmp ax,'pr' ; PRompt
1256 0000048E 0F84AD00 je near pc_prompt
1257 00000492 3D666F cmp ax,'fo' ; FOnt
1258 00000495 0F84CE01 je near pc_font
1259 00000499 3D6B62 cmp ax,'kb' ; KBd
1260 0000049C 0F84D101 je near pc_kbd
1261 000004A0 3D6469 cmp ax,'di' ; DIsplay
1262 000004A3 0F848D00 je near pc_display
1263 000004A7 3D6C61 cmp ax,'la' ; LAbel
1264 000004AA 0F848601 je near pc_label
1265 000004AE 3D6B65 cmp ax,'ke' ; KErnel
1266 000004B1 7456 je pc_kernel
1267 000004B3 3D696D cmp ax,'im' ; IMplicit
1268 000004B6 0F849000 je near pc_implicit
1269 000004BA 3D7365 cmp ax,'se' ; SErial
1270 000004BD 0F849400 je near pc_serial
1271 000004C1 3C66 cmp al,'f' ; F-key
1272 000004C3 75AE jne parse_config
1273 000004C5 E94201 jmp pc_fkey
1274
1275 000004C8 BF[951E] pc_default: mov di,default_cmd ; "default" command
1276 000004CB E83D11 call getline
1277 000004CE 30C0 xor al,al
1278 000004D0 AA stosb ; null-terminate
1279 000004D1 EBA0 jmp short parse_config
1280
1281 000004D3 833E[5A1D]00 pc_append: cmp word [VKernelCtr],byte 0 ; "append" command
1282 000004D8 7710 ja pc_append_vk
1283 000004DA BF0052 mov di,AppendBuf
1284 000004DD E82B11 call getline
1285 000004E0 81EF0052 sub di,AppendBuf
1286 000004E4 893E[501D] pc_app1: mov [AppendLen],di
1287 000004E8 EB89 jmp short parse_config
1288 000004EA BF1850 pc_append_vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel)
1289 000004ED E81B11 call getline
1290 000004F0 81EF1850 sub di,VKernelBuf+vk_append
1291 000004F4 83FF02 cmp di,byte 2
1292 000004F7 750A jne pc_app2
1293 000004F9 803E18502D cmp byte [VKernelBuf+vk_append],'-'
1294 000004FE 7503 jne pc_app2
1295 00000500 BF0000 mov di,0 ; If "append -" -> null string
1296 00000503 893E1650 pc_app2: mov [VKernelBuf+vk_appendlen],di
1297 00000507 EB33 jmp short parse_config_2
1298
1299 00000509 833E[5A1D]00 pc_kernel: cmp word [VKernelCtr],byte 0 ; "kernel" command
1300 0000050E 0F8461FF je near parse_config ; ("label" section only)
1301 00000512 BF0010 mov di,trackbuf
1302 00000515 57 push di
1303 00000516 E8F210 call getline
1304 00000519 5E pop si
1305 0000051A BF0B50 mov di,VKernelBuf+vk_rname
1306 0000051D E82811 call mangle_name
1307 00000520 EB1A jmp short parse_config_2
1308
1309 00000522 E83110 pc_timeout: call getint ; "timeout" command
1310 00000525 7215 jc parse_config_2
1311 00000527 B815D2 mov ax,0D215h ; There are approx 1.D215h
1312 0000052A F7E3 mul bx ; clock ticks per 1/10 s
1313 0000052C 01D3 add bx,dx
1314 0000052E 891E[521D] mov [KbdTimeOut],bx
1315 00000532 EB08 jmp short parse_config_2
1316
1317 00000534 E84501 pc_display: call pc_getfile ; "display" command
1318 00000537 7403 jz parse_config_2 ; File not found?
1319 00000539 E8B50C call get_msg_file ; Load and display file
1320 0000053C E934FF parse_config_2: jmp parse_config
1321
1322 0000053F E81410 pc_prompt: call getint ; "prompt" command
1323 00000542 72F8 jc parse_config_2
1324 00000544 891E[5C1D] mov [ForcePrompt],bx
1325 00000548 EBF2 jmp short parse_config_2
1326
1327 0000054A E80910 pc_implicit: call getint ; "implicit" command
1328 0000054D 72ED jc parse_config_2
1329 0000054F 891E[5E1D] mov [AllowImplicit],bx
1330 00000553 EBE7 jmp short parse_config_2
1331
1332 00000555 E8FE0F pc_serial: call getint ; "serial" command
1333 00000558 72E2 jc parse_config_2
1334 0000055A 53 push bx ; Serial port #
1335 0000055B E8830F call skipspace
1336 0000055E 72DC jc parse_config_2
1337 00000560 E86D0F call ungetc
1338 00000563 E8F00F call getint
1339 00000566 C70642550000 mov [FlowControl], word 0 ; Default to no flow control
1340 0000056C 7229 jc .nobaud
1341 .valid_baud:
1342 0000056E 6653 push ebx
1343 00000570 E86E0F call skipspace
1344 00000573 7208 jc .no_flow
1345 00000575 E8580F call ungetc
1346 00000578 E8DB0F call getint ; Hardware flow control?
1347 0000057B 7302 jnc .valid_flow
1348 .no_flow:
1349 0000057D 31DB xor bx,bx ; Default -> no flow control
1350 .valid_flow:
1351 0000057F 80E70F and bh,0Fh ; FlowIgnore
1352 00000582 C0E704 shl bh,4
1353 00000585 883E4455 mov [FlowIgnore],bh
1354 00000589 88DF mov bh,bl
1355 0000058B 81E303F0 and bx,0F003h ; Valid bits
1356 0000058F 891E4255 mov [FlowControl],bx
1357 00000593 665B pop ebx ; Baud rate
1358 00000595 EB06 jmp short .parse_baud
1359 .nobaud:
1360 00000597 66BB80250000 mov ebx,DEFAULT_BAUD ; No baud rate given
1361 .parse_baud:
1362 0000059D 5F pop di ; Serial port #
1363 0000059E 6683FB4B cmp ebx,byte 75
1364 000005A2 7298 jb parse_config_2 ; < 75 baud == bogus
1365 000005A4 66B800C20100 mov eax,BAUD_DIVISOR
1366 000005AA 6699 cdq
1367 000005AC 66F7F3 div ebx
1368 000005AF 50 push ax ; Baud rate divisor
1369 000005B0 81FF0300 cmp di,3
1370 000005B4 7706 ja .port_is_io ; If port > 3 then port is I/O addr
1371 000005B6 D1E7 shl di,1
1372 000005B8 8BBD0004 mov di,[di+serial_base] ; Get the I/O port from the BIOS
1373 .port_is_io:
1374 000005BC 893E[601D] mov [SerialPort],di
1375 000005C0 8D5503 lea dx,[di+3] ; DX -> LCR
1376 000005C3 B083 mov al,83h ; Enable DLAB
1377 000005C5 E83509 call slow_out
1378 000005C8 58 pop ax ; Divisor
1379 000005C9 89FA mov dx,di ; DX -> LS
1380 000005CB E82F09 call slow_out
1381 000005CE 42 inc dx ; DX -> MS
1382 000005CF 88E0 mov al,ah
1383 000005D1 E82909 call slow_out
1384 000005D4 B003 mov al,03h ; Disable DLAB
1385 000005D6 83C202 add dx,byte 2 ; DX -> LCR
1386 000005D9 E82109 call slow_out
1387 000005DC EC in al,dx ; Read back LCR (detect missing hw)
1388 000005DD 3C03 cmp al,03h ; If nothing here we'll read 00 or FF
1389 000005DF 7521 jne .serial_port_bad ; Assume serial port busted
1390 000005E1 83EA02 sub dx,byte 2 ; DX -> IER
1391 000005E4 30C0 xor al,al ; IRQ disable
1392 000005E6 E81409 call slow_out
1393
1394 000005E9 83C203 add dx,byte 3 ; DX -> MCR
1395 000005EC EC in al,dx
1396 000005ED 0A064255 or al,[FlowOutput] ; Assert bits
1397 000005F1 E80909 call slow_out
1398
1399 ; Show some life
1400 000005F4 BE[0002] mov si,syslinux_banner
1401 000005F7 E8C10D call write_serial_str
1402 000005FA BE[F318] mov si,copyright_str
1403 000005FD E8BB0D call write_serial_str
1404
1405 00000600 EB77 jmp short parse_config_3
1406
1407 .serial_port_bad:
1408 00000602 C706[601D]0000 mov [SerialPort], word 0
1409 00000608 EB6F jmp short parse_config_3
1410
1411 0000060A 80EC31 pc_fkey: sub ah,'1'
1412 0000060D 7302 jnb pc_fkey1
1413 0000060F B409 mov ah,9 ; F10
1414 00000611 31C9 pc_fkey1: xor cx,cx
1415 00000613 88E1 mov cl,ah
1416 00000615 51 push cx
1417 00000616 B80100 mov ax,1
1418 00000619 D3E0 shl ax,cl
1419 0000061B 0906[541D] or [FKeyMap], ax ; Mark that we have this loaded
1420 0000061F BF0010 mov di,trackbuf
1421 00000622 57 push di
1422 00000623 E8E50F call getline ; Get filename to display
1423 00000626 5E pop si
1424 00000627 5F pop di
1425 00000628 C1E704 shl di,4 ; Multiply number by 16
1426 0000062B 81C70054 add di,FKeyName
1427 0000062F E81610 call mangle_name ; Mangle file name
1428 00000632 EB45 jmp short parse_config_3
1429
1430 00000634 E85800 pc_label: call commit_vk ; Commit any current vkernel
1431 00000637 BF0010 mov di,trackbuf ; Get virtual filename
1432 0000063A 57 push di
1433 0000063B E8CD0F call getline
1434 0000063E 5E pop si
1435 0000063F BF0050 mov di,VKernelBuf+vk_vname
1436 00000642 E80310 call mangle_name ; Mangle virtual name
1437 00000645 FF06[5A1D] inc word [VKernelCtr] ; One more vkernel
1438 00000649 BE0050 mov si,VKernelBuf+vk_vname ; By default, rname == vname
1439 0000064C BF0B50 mov di,VKernelBuf+vk_rname
1440 0000064F B90B00 mov cx,11
1441 00000652 F3A4 rep movsb
1442 00000654 BE0052 mov si,AppendBuf ; Default append==global append
1443 00000657 BF1850 mov di,VKernelBuf+vk_append
1444 0000065A 8B0E[501D] mov cx,[AppendLen]
1445 0000065E 890E1650 mov [VKernelBuf+vk_appendlen],cx
1446 00000662 F3A4 rep movsb
1447 00000664 E91200 jmp near parse_config_3
1448
1449 00000667 E81200 pc_font: call pc_getfile ; "font" command
1450 0000066A 740D jz parse_config_3 ; File not found?
1451 0000066C E8C40A call loadfont ; Load and install font
1452 0000066F EB08 jmp short parse_config_3
1453
1454 00000671 E80800 pc_kbd: call pc_getfile ; "kbd" command
1455 00000674 7403 jz parse_config_3
1456 00000676 E8590B call loadkeys
1457 00000679 E9F7FD parse_config_3: jmp parse_config
1458
1459 ;
1460 ; pc_getfile: For command line options that take file argument, this
1461 ; routine decodes the file argument and runs it through searchdir
1462 ;
1463 0000067C BF0010 pc_getfile: mov di,trackbuf
1464 0000067F 57 push di
1465 00000680 E8880F call getline
1466 00000683 5E pop si
1467 00000684 BF4B55 mov di,MNameBuf
1468 00000687 57 push di
1469 00000688 E8BD0F call mangle_name
1470 0000068B 5F pop di
1471 0000068C E9210A jmp searchdir ; Tailcall
1472
1473 ;
1474 ; commit_vk: Store the current VKernelBuf into buffer segment
1475 ;
1476 commit_vk:
1477 0000068F 833E[5A1D]00 cmp word [VKernelCtr],byte 0
1478 00000694 741F je cvk_ret ; No VKernel = return
1479 00000696 813E[5A1D]8000 cmp word [VKernelCtr],max_vk ; Above limit?
1480 0000069C 7718 ja cvk_overflow
1481 0000069E 8B3E[5A1D] mov di,[VKernelCtr]
1482 000006A2 4F dec di
1483 000006A3 C1E709 shl di,vk_shift
1484 000006A6 BE0050 mov si,VKernelBuf
1485 000006A9 B98000 mov cx,(vk_size >> 2)
1486 000006AC 06 push es
1487 000006AD 680040 push word vk_seg
1488 000006B0 07 pop es
1489 000006B1 F366A5 rep movsd ; Copy to buffer segment
1490 000006B4 07 pop es
1491 000006B5 C3 cvk_ret: ret
1492 000006B6 C706[5A1D]8000 cvk_overflow: mov word [VKernelCtr],max_vk ; No more than max_vk, please
1493 000006BC C3 ret
1494
1495 ;
1496 ; End of configuration file
1497 ;
1498 end_config_file:
1499 000006BD E8CFFF call commit_vk ; Commit any current vkernel
1500 no_config_file:
1501 ;
1502 ; Check whether or not we are supposed to display the boot prompt.
1503 ;
1504 check_for_key:
1505 000006C0 833E[5C1D]00 cmp word [ForcePrompt],byte 0 ; Force prompt?
1506 000006C5 7509 jnz enter_command
1507 000006C7 F60646555B test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt
1508 000006CC 0F84FA00 jz near auto_boot ; If neither, default boot
1509
1510 enter_command:
1511 000006D0 BE[1D19] mov si,boot_prompt
1512 000006D3 E8060D call cwritestr
1513
1514 000006D6 C606495500 mov byte [FuncFlag],0 ; <Ctrl-F> not pressed
1515 000006DB BF[941D] mov di,command_line
1516 ;
1517 ; get the very first character -- we can either time
1518 ; out, or receive a character press at this time. Some dorky BIOSes stuff
1519 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
1520 ;
1521 000006DE B401 clear_buffer: mov ah,1 ; Check for pending char
1522 000006E0 CD16 int 16h
1523 000006E2 7406 jz get_char_time
1524 000006E4 31C0 xor ax,ax ; Get char
1525 000006E6 CD16 int 16h
1526 000006E8 EBF4 jmp short clear_buffer
1527 get_char_time:
1528 000006EA E8B011 call vgashowcursor
1529 000006ED 8B0E[521D] mov cx,[KbdTimeOut]
1530 000006F1 21C9 and cx,cx
1531 000006F3 741C jz get_char ; Timeout == 0 -> no timeout
1532 000006F5 41 inc cx ; The first loop will happen
1533 ; immediately as we don't
1534 ; know the appropriate DX value
1535 000006F6 51 time_loop: push cx
1536 000006F7 52 tick_loop: push dx
1537 000006F8 E8F40C call pollchar
1538 000006FB 7512 jnz get_char_pop
1539 000006FD 31C0 xor ax,ax
1540 000006FF CD1A int 1Ah ; Get time "of day"
1541 00000701 58 pop ax
1542 00000702 39C2 cmp dx,ax ; Has the timer advanced?
1543 00000704 74F1 je tick_loop
1544 00000706 59 pop cx
1545 00000707 E2ED loop time_loop ; If so, decrement counter
1546 00000709 E89711 call vgahidecursor
1547 0000070C E9C900 jmp command_done ; Timeout!
1548
1549 0000070F 6658 get_char_pop: pop eax ; Clear stack
1550 get_char:
1551 00000711 E88911 call vgashowcursor
1552 00000714 E8020D call getchar
1553 00000717 E88911 call vgahidecursor
1554 0000071A 20C0 and al,al
1555 0000071C 7462 jz func_key
1556
1557 0000071E 3C7F got_ascii: cmp al,7Fh ; <DEL> == <BS>
1558 00000720 743F je backspace
1559 00000722 3C20 cmp al,' ' ; ASCII?
1560 00000724 722A jb not_ascii
1561 00000726 7706 ja enter_char
1562 00000728 81FF[941D] cmp di,command_line ; Space must not be first
1563 0000072C 74E3 je get_char
1564 0000072E F606495501 enter_char: test byte [FuncFlag],1
1565 00000733 740F jz .not_ctrl_f
1566 00000735 C606495500 mov byte [FuncFlag],0
1567 0000073A 3C30 cmp al,'0'
1568 0000073C 7206 jb .not_ctrl_f
1569 0000073E 7437 je ctrl_f_0
1570 00000740 3C39 cmp al,'9'
1571 00000742 7635 jbe ctrl_f
1572 00000744 81FF[931E] .not_ctrl_f: cmp di,max_cmd_len+command_line ; Check there's space
1573 00000748 73C7 jnb get_char
1574 0000074A AA stosb ; Save it
1575 0000074B E8780C call writechr ; Echo to screen
1576 0000074E EBC1 get_char_2: jmp short get_char
1577 00000750 C606495500 not_ascii: mov byte [FuncFlag],0
1578 00000755 3C0D cmp al,0Dh ; Enter
1579 00000757 747F je command_done
1580 00000759 3C06 cmp al,06h ; <Ctrl-F>
1581 0000075B 7413 je set_func_flag
1582 0000075D 3C08 cmp al,08h ; Backspace
1583 0000075F 75B0 jne get_char
1584 00000761 81FF[941D] backspace: cmp di,command_line ; Make sure there is anything
1585 00000765 74AA je get_char ; to erase
1586 00000767 4F dec di ; Unstore one character
1587 00000768 BE[2419] mov si,wipe_char ; and erase it from the screen
1588 0000076B E86E0C call cwritestr
1589 0000076E EBDE jmp short get_char_2
1590
1591 set_func_flag:
1592 00000770 C606495501 mov byte [FuncFlag],1
1593 00000775 EBD7 jmp short get_char_2
1594
1595 00000777 040A ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10
1596 00000779 57 ctrl_f: push di
1597 0000077A 2C31 sub al,'1'
1598 0000077C 30E4 xor ah,ah
1599 0000077E EB0E jmp short show_help
1600
1601 func_key:
1602 00000780 57 push di
1603 00000781 80FC44 cmp ah,68 ; F10
1604 00000784 77C8 ja get_char_2
1605 00000786 80EC3B sub ah,59 ; F1
1606 00000789 72C3 jb get_char_2
1607 0000078B C1E808 shr ax,8
1608 show_help: ; AX = func key # (0 = F1, 9 = F10)
1609 0000078E 88C1 mov cl,al
1610 00000790 C1E004 shl ax,4 ; Convert to x16
1611 00000793 BB0100 mov bx,1
1612 00000796 D3E3 shl bx,cl
1613 00000798 231E[541D] and bx,[FKeyMap]
1614 0000079C 74B0 jz get_char_2 ; Undefined F-key
1615 0000079E 89C7 mov di,ax
1616 000007A0 81C70054 add di,FKeyName
1617 000007A4 E80909 call searchdir
1618 000007A7 740A jz fk_nofile
1619 000007A9 56 push si
1620 000007AA E82C0C call crlf
1621 000007AD 5E pop si
1622 000007AE E8400A call get_msg_file
1623 000007B1 EB03 jmp short fk_wrcmd
1624 fk_nofile:
1625 000007B3 E8230C call crlf
1626 fk_wrcmd:
1627 000007B6 BE[1D19] mov si,boot_prompt
1628 000007B9 E8200C call cwritestr
1629 000007BC 5F pop di ; Command line write pointer
1630 000007BD 57 push di
1631 000007BE C60500 mov byte [di],0 ; Null-terminate command line
1632 000007C1 BE[941D] mov si,command_line
1633 000007C4 E8150C call cwritestr ; Write command line so far
1634 000007C7 5F pop di
1635 000007C8 EB84 jmp short get_char_2
1636 auto_boot:
1637 000007CA BE[951E] mov si,default_cmd
1638 000007CD BF[941D] mov di,command_line
1639 000007D0 B94000 mov cx,(max_cmd_len+4) >> 2
1640 000007D3 F366A5 rep movsd
1641 000007D6 EB0C jmp short load_kernel
1642 command_done:
1643 000007D8 E8FE0B call crlf
1644 000007DB 81FF[941D] cmp di,command_line ; Did we just hit return?
1645 000007DF 74E9 je auto_boot
1646 000007E1 30C0 xor al,al ; Store a final null
1647 000007E3 AA stosb
1648
1649 load_kernel: ; Load the kernel now
1650 ;
1651 ; First we need to mangle the kernel name the way DOS would...
1652 ;
1653 000007E4 BE[941D] mov si,command_line
1654 000007E7 BFE854 mov di,KernelName
1655 000007EA 56 push si
1656 000007EB 57 push di
1657 000007EC E8590E call mangle_name
1658 000007EF 5F pop di
1659 000007F0 5E pop si
1660 ;
1661 ; Fast-forward to first option (we start over from the beginning, since
1662 ; mangle_name doesn't necessarily return a consistent ending state.)
1663 ;
1664 000007F1 AC clin_non_wsp: lodsb
1665 000007F2 3C20 cmp al,' '
1666 000007F4 77FB ja clin_non_wsp
1667 000007F6 20C0 clin_is_wsp: and al,al
1668 000007F8 7405 jz clin_opt_ptr
1669 000007FA AC lodsb
1670 000007FB 3C20 cmp al,' '
1671 000007FD 76F7 jbe clin_is_wsp
1672 000007FF 4E clin_opt_ptr: dec si ; Point to first nonblank
1673 00000800 89362455 mov [CmdOptPtr],si ; Save ptr to first option
1674 ;
1675 ; Now check if it is a "virtual kernel"
1676 ;
1677 00000804 8B0E[5A1D] mov cx,[VKernelCtr]
1678 00000808 1E push ds
1679 00000809 680040 push word vk_seg
1680 0000080C 1F pop ds
1681 0000080D 83F900 cmp cx,byte 0
1682 00000810 7413 je not_vk
1683 00000812 31F6 xor si,si ; Point to first vkernel
1684 00000814 60 vk_check: pusha
1685 00000815 B90B00 mov cx,11
1686 00000818 F3A6 repe cmpsb ; Is this it?
1687 0000081A 0F847700 je near vk_found
1688 0000081E 61 popa
1689 0000081F 81C60002 add si,vk_size
1690 00000823 E2EF loop vk_check
1691 00000825 1F not_vk: pop ds
1692 ;
1693 ; Not a "virtual kernel" - check that's OK and construct the command line
1694 ;
1695 00000826 833E[5E1D]00 cmp word [AllowImplicit],byte 0
1696 0000082B 745D je bad_implicit
1697 0000082D 06 push es
1698 0000082E 56 push si
1699 0000082F 57 push di
1700 00000830 BF0070 mov di,real_mode_seg
1701 00000833 8EC7 mov es,di
1702 00000835 BE0052 mov si,AppendBuf
1703 00000838 BF0090 mov di,cmd_line_here
1704 0000083B 8B0E[501D] mov cx,[AppendLen]
1705 0000083F F3A4 rep movsb
1706 00000841 893E[561D] mov [CmdLinePtr],di
1707 00000845 5F pop di
1708 00000846 5E pop si
1709 00000847 07 pop es
1710 00000848 BB1000 mov bx,exten_count << 2 ; Alternates to try
1711 ;
1712 ; Find the kernel on disk
1713 ;
1714 0000084B C606F35400 get_kernel: mov byte [KernelName+11],0 ; Zero-terminate filename/extension
1715 00000850 66A1F054 mov eax,[KernelName+8] ; Save initial extension
1716 00000854 66A3[3C1D] mov [OrigKernelExt],eax
1717 00000858 53 .search_loop: push bx
1718 00000859 BFE854 mov di,KernelName ; Search on disk
1719 0000085C E85108 call searchdir
1720 0000085F 5B pop bx
1721 00000860 756C jnz kernel_good
1722 00000862 668B87[3C1D] mov eax,[exten_table+bx] ; Try a different extension
1723 00000867 66A3F054 mov [KernelName+8],eax
1724 0000086B 83EB04 sub bx,byte 4
1725 0000086E 73E8 jnb .search_loop
1726 bad_kernel:
1727 00000870 BEE854 mov si,KernelName
1728 00000873 BF6155 mov di,KernelCName
1729 00000876 57 push di
1730 00000877 E82A0E call unmangle_name ; Get human form
1731 0000087A BE[2819] mov si,err_notfound ; Complain about missing kernel
1732 0000087D E85C0B call cwritestr
1733 00000880 5E pop si ; KernelCName
1734 00000881 E8580B call cwritestr
1735 00000884 BE[F81C] mov si,crlf_msg
1736 00000887 E91108 jmp abort_load ; Ask user for clue
1737 ;
1738 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
1739 ;
1740 0000088A BEE854 bad_implicit: mov si,KernelName ; For the error message
1741 0000088D BF6155 mov di,KernelCName
1742 00000890 E8110E call unmangle_name
1743 00000893 EBDB jmp short bad_kernel
1744 ;
1745 ; vk_found: We *are* using a "virtual kernel"
1746 ;
1747 00000895 61 vk_found: popa
1748 00000896 57 push di
1749 00000897 BF0050 mov di,VKernelBuf
1750 0000089A B98000 mov cx,vk_size >> 2
1751 0000089D F366A5 rep movsd
1752 000008A0 06 push es ; Restore old DS
1753 000008A1 1F pop ds
1754 000008A2 06 push es
1755 000008A3 680070 push word real_mode_seg
1756 000008A6 07 pop es
1757 000008A7 BF0090 mov di,cmd_line_here
1758 000008AA BE1850 mov si,VKernelBuf+vk_append
1759 000008AD 8B0E1650 mov cx,[VKernelBuf+vk_appendlen]
1760 000008B1 F3A4 rep movsb
1761 000008B3 893E[561D] mov [CmdLinePtr],di ; Where to add rest of cmd
1762 000008B7 07 pop es
1763 000008B8 5F pop di ; DI -> KernelName
1764 000008B9 57 push di
1765 000008BA BE0B50 mov si,VKernelBuf+vk_rname
1766 000008BD B90B00 mov cx,11 ; We need ECX == CX later
1767 000008C0 F3A4 rep movsb
1768 000008C2 5F pop di
1769 000008C3 31DB xor bx,bx ; Try only one version
1770 000008C5 E983FF jmp get_kernel
1771 ;
1772 ; kernel_corrupt: Called if the kernel file does not seem healthy
1773 ;
1774 000008C8 BE[4619] kernel_corrupt: mov si,err_notkernel
1775 000008CB E9CD07 jmp abort_load
1776 ;
1777 ; This is it! We have a name (and location on the disk)... let's load
1778 ; that sucker!! First we have to decide what kind of file this is; base
1779 ; that decision on the file extension. The following extensions are
1780 ; recognized:
1781 ;
1782 ; .COM - COMBOOT image
1783 ; .CBT - COMBOOT image
1784 ; .BS - Boot sector
1785 ; .BSS - Boot sector, but transfer over DOS superblock
1786 ;
1787 ; Anything else is assumed to be a Linux kernel.
1788 ;
1789 kernel_good:
1790 000008CE 60 pusha
1791 000008CF BEE854 mov si,KernelName
1792 000008D2 BF6155 mov di,KernelCName
1793 000008D5 E8CC0D call unmangle_name ; Get human form
1794 000008D8 81EF6155 sub di,KernelCName
1795 000008DC 893E2655 mov [KernelCNameLen],di
1796 000008E0 61 popa
1797
1798 000008E1 668B0EF054 mov ecx,[KernelName+8] ; Get (mangled) extension
1799 000008E6 6681F9434F4D00 cmp ecx,'COM'
1800 000008ED 0F847C04 je near is_comboot_image
1801 000008F1 6681F943425400 cmp ecx,'CBT'
1802 000008F8 0F847104 je near is_comboot_image
1803 000008FC 6681F942532000 cmp ecx,'BS '
1804 00000903 0F841B05 je near is_bootsector
1805 00000907 6681F942535300 cmp ecx,'BSS'
1806 0000090E 0F841505 je near is_bss_sector
1807 ; Otherwise Linux kernel
1808 ;
1809 ; A Linux kernel consists of three parts: boot sector, setup code, and
1810 ; kernel code. The boot sector is never executed when using an external
1811 ; booting utility, but it contains some status bytes that are necessary.
1812 ; The boot sector and setup code together form exactly 5 sectors that
1813 ; should be loaded at 9000:0. The subsequent code should be loaded
1814 ; at 1000:0. For simplicity, we load the whole thing at 0F60:0, and
1815 ; copy the latter stuff afterwards.
1816 ;
1817 ; NOTE: In the previous code I have avoided making any assumptions regarding
1818 ; the size of a sector, in case this concept ever gets extended to other
1819 ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT
1820 ; filesystem, of course). However, a "sector" when it comes to Linux booting
1821 ; stuff means 512 bytes *no matter what*, so here I am using that piece
1822 ; of knowledge.
1823 ;
1824 ; First check that our kernel is at least 1K and less than 8M (if it is
1825 ; more than 8M, we need to change the logic for loading it anyway...)
1826 ;
1827 ; We used to require the kernel to be 64K or larger, but it has gotten
1828 ; popular to use the Linux kernel format for other things, which may
1829 ; not be so large.
1830 ;
1831 is_linux_kernel:
1832 00000912 81FA8000 cmp dx,80h ; 8 megs
1833 00000916 77B0 ja kernel_corrupt
1834 00000918 21D2 and dx,dx
1835 0000091A 7505 jnz kernel_sane
1836 0000091C 3D0004 cmp ax,1024 ; Bootsect + 1 setup sect
1837 0000091F 72A7 jb kernel_corrupt
1838 00000921 50 kernel_sane: push ax
1839 00000922 52 push dx
1840 00000923 56 push si
1841 00000924 BE[E31C] mov si,loading_msg
1842 00000927 E8B20A call cwritestr
1843 ;
1844 ; Now start transferring the kernel
1845 ;
1846 0000092A 680070 push word real_mode_seg
1847 0000092D 07 pop es
1848
1849 0000092E 50 push ax
1850 0000092F 52 push dx
1851 00000930 F7360A55 div word [ClustSize] ; # of clusters total
1852 00000934 21D2 and dx,dx ; Round up
1853 00000936 0F95C2 setnz dl
1854 00000939 0FB6D2 movzx dx,dl
1855 0000093C 01D0 add ax,dx
1856 0000093E A31855 mov [KernelClust],ax
1857 00000941 5A pop dx
1858 00000942 58 pop ax
1859 00000943 A3E454 mov [KernelSize],ax
1860 00000946 8916E654 mov [KernelSize+2],dx
1861 ;
1862 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
1863 ; have to see if we're loading more than 64K, and if so, load it step by
1864 ; step.
1865 ;
1866 0000094A BA0100 mov dx,1 ; 10000h
1867 0000094D 31C0 xor ax,ax
1868 0000094F F7360A55 div word [ClustSize]
1869 00000953 A31C55 mov [ClustPerMoby],ax ; Clusters/64K
1870 ;
1871 ; Start by loading the bootsector/setup code, to see if we need to
1872 ; do something funky. It should fit in the first 32K (loading 64K won't
1873 ; work since we might have funny stuff up near the end of memory).
1874 ; If we have larger than 32K clusters, yes, we're hosed.
1875 ;
1876 00000956 E82E07 call abort_check ; Check for abort key
1877 00000959 8B0E1C55 mov cx,[ClustPerMoby]
1878 0000095D D1E9 shr cx,1 ; Half a moby
1879 0000095F 3B0E1855 cmp cx,[KernelClust]
1880 00000963 7604 jna .normalkernel
1881 00000965 8B0E1855 mov cx,[KernelClust]
1882 .normalkernel:
1883 00000969 290E1855 sub [KernelClust],cx
1884 0000096D 31DB xor bx,bx
1885 0000096F 5E pop si ; Cluster pointer on stack
1886 00000970 E8B3F9 call getfssec
1887 00000973 26813EFE0155AA cmp word [es:bs_bootsign],0AA55h
1888 0000097A 0F854AFF jne near kernel_corrupt ; Boot sec signature missing
1889 ;
1890 ; Get the BIOS' idea of what the size of high memory is.
1891 ;
1892 0000097E 56 push si ; Save our cluster pointer!
1893 ;
1894 ; First, try INT 15:E820 (get BIOS memory map)
1895 ;
1896 get_e820:
1897 0000097F 06 push es
1898 00000980 6631DB xor ebx,ebx ; Start with first record
1899 00000983 8EC3 mov es,bx ; Need ES = DS = 0 for now
1900 00000985 EB05 jmp short .do_e820 ; Skip "at end" check first time!
1901 00000987 6621DB .int_loop: and ebx,ebx ; If we're back at beginning...
1902 0000098A 745A jz no_e820 ; ... bail; nothing found
1903 0000098C 66B820E80000 .do_e820: mov eax,0000E820h
1904 00000992 66BA50414D53 mov edx,534D4150h ; "SMAP" backwards
1905 00000998 66B914000000 mov ecx,20
1906 0000099E BFC054 mov di,E820Buf
1907 000009A1 CD15 int 15h
1908 000009A3 7241 jc no_e820
1909 000009A5 663D50414D53 cmp eax,534D4150h
1910 000009AB 7539 jne no_e820
1911 ;
1912 ; Look for a memory block starting at <= 1 MB and continuing upward
1913 ;
1914 000009AD 66833EC45400 cmp dword [E820Buf+4], byte 0
1915 000009B3 77D2 ja .int_loop ; Start >= 4 GB?
1916 000009B5 66BA00001000 mov edx, (1 << 20)
1917 000009BB 662B16C054 sub edx, [E820Buf]
1918 000009C0 72C5 jb .int_loop ; Start >= 1 MB?
1919 000009C2 66B8FFFFFFFF mov eax, 0FFFFFFFFh
1920 000009C8 66833ECC5400 cmp dword [E820Buf+12], byte 0
1921 000009CE 7704 ja .huge ; Size >= 4 GB
1922 000009D0 66A1C854 mov eax, [E820Buf+8]
1923 000009D4 6629D0 .huge: sub eax, edx ; Adjust size to start at 1 MB
1924 000009D7 76AE jbe .int_loop ; Completely below 1 MB?
1925
1926 ; Now EAX contains the size of memory 1 MB...up
1927 000009D9 66833ED05401 cmp dword [E820Buf+16], byte 1
1928 000009DF 0F85B911 jne near err_nohighmem ; High memory isn't usable memory!!!!
1929
1930 ; We're good!
1931 000009E3 07 pop es
1932 000009E4 EB33 jmp short got_highmem_add1mb ; Still need to add low 1 MB
1933
1934 ;
1935 ; INT 15:E820 failed. Try INT 15:E801.
1936 ;
1937 000009E6 07 no_e820: pop es
1938
1939 000009E7 B801E8 mov ax,0e801h ; Query high memory (semi-recent)
1940 000009EA CD15 int 15h
1941 000009EC 7215 jc no_e801
1942 000009EE 3D003C cmp ax,3c00h
1943 000009F1 7710 ja no_e801 ; > 3C00h something's wrong with this call
1944 000009F3 721A jb e801_hole ; If memory hole we can only use low part
1945
1946 000009F5 89D8 mov ax,bx
1947 000009F7 66C1E010 shl eax,16 ; 64K chunks
1948 000009FB 660500000001 add eax,(16 << 20) ; Add first 16M
1949 00000A01 EB1C jmp short got_highmem
1950
1951 ;
1952 ; INT 15:E801 failed. Try INT 15:88.
1953 ;
1954 no_e801:
1955 00000A03 B488 mov ah,88h ; Query high memory (oldest)
1956 00000A05 CD15 int 15h
1957 00000A07 3D0038 cmp ax,14*1024 ; Don't trust memory >15M
1958 00000A0A 7603 jna e801_hole
1959 00000A0C B80038 mov ax,14*1024
1960 e801_hole:
1961 00000A0F 6625FFFF0000 and eax,0ffffh
1962 00000A15 66C1E00A shl eax,10 ; Convert from kilobytes
1963 got_highmem_add1mb:
1964 00000A19 660500001000 add eax,(1 << 20) ; First megabyte
1965 got_highmem:
1966 00000A1F 66A3DC54 mov [HighMemSize],eax
1967
1968 ;
1969 ; Construct the command line (append options have already been copied)
1970 ;
1971 00000A23 8B3E[561D] mov di,[CmdLinePtr]
1972 00000A27 BE[871D] mov si,boot_image ; BOOT_IMAGE=
1973 00000A2A B90B00 mov cx,boot_image_len
1974 00000A2D F3A4 rep movsb
1975 00000A2F BE6155 mov si,KernelCName ; Unmangled kernel name
1976 00000A32 8B0E2655 mov cx,[KernelCNameLen]
1977 00000A36 F3A4 rep movsb
1978 00000A38 B020 mov al,' ' ; Space
1979 00000A3A AA stosb
1980 00000A3B 8B362455 mov si,[CmdOptPtr] ; Options from user input
1981 00000A3F B98100 mov cx,(kern_cmd_len+3) >> 2
1982 00000A42 F366A5 rep movsd
1983 ;
1984 %ifdef debug
1985 push ds ; DEBUG DEBUG DEBUG
1986 push es
1987 pop ds
1988 mov si,cmd_line_here
1989 call cwritestr
1990 pop ds
1991 call crlf
1992 %endif
1993 ;
1994 ; Scan through the command line for anything that looks like we might be
1995 ; interested in. The original version of this code automatically assumed
1996 ; the first option was BOOT_IMAGE=, but that is no longer certain.
1997 ;
1998 00000A45 BE0090 mov si,cmd_line_here
1999 00000A48 C606[581D]00 mov byte [initrd_flag],0
2000 00000A4D 06 push es ; Set DS <- real_mode_seg
2001 00000A4E 1F pop ds
2002 00000A4F AC get_next_opt: lodsb
2003 00000A50 20C0 and al,al
2004 00000A52 0F848A00 jz near cmdline_end
2005 00000A56 3C20 cmp al,' '
2006 00000A58 76F5 jbe get_next_opt
2007 00000A5A 4E dec si
2008 00000A5B 668B04 mov eax,[si]
2009 00000A5E 663D7667613D cmp eax,'vga='
2010 00000A64 7432 je is_vga_cmd
2011 00000A66 663D6D656D3D cmp eax,'mem='
2012 00000A6C 7462 je is_mem_cmd
2013 00000A6E 06 push es ; Save ES -> real_mode_seg
2014 00000A6F 16 push ss
2015 00000A70 07 pop es ; Set ES <- normal DS
2016 00000A71 BF[091D] mov di,initrd_cmd
2017 00000A74 B90700 mov cx,initrd_cmd_len
2018 00000A77 F3A6 repe cmpsb
2019 00000A79 7514 jne not_initrd
2020 00000A7B BF5655 mov di,InitRD
2021 00000A7E 56 push si ; mangle_dir mangles si
2022 00000A7F E8C60B call mangle_name ; Mangle ramdisk name
2023 00000A82 5E pop si
2024 00000A83 26803E565520 cmp byte [es:InitRD],' ' ; Null filename?
2025 00000A89 260F9706[581D] seta byte [es:initrd_flag] ; Set flag if not
2026 00000A8F 07 not_initrd: pop es ; Restore ES -> real_mode_seg
2027 00000A90 AC skip_this_opt: lodsb ; Load from command line
2028 00000A91 3C20 cmp al,' '
2029 00000A93 77FB ja skip_this_opt
2030 00000A95 4E dec si
2031 00000A96 EBB7 jmp short get_next_opt
2032 is_vga_cmd:
2033 00000A98 83C604 add si,byte 4
2034 00000A9B 668B04 mov eax,[si]
2035 00000A9E BBFFFF mov bx,-1
2036 00000AA1 663D6E6F726D cmp eax, 'norm' ; vga=normal
2037 00000AA7 7421 je vc0
2038 00000AA9 6625FFFFFF00 and eax,0ffffffh ; 3 bytes
2039 00000AAF BBFEFF mov bx,-2
2040 00000AB2 663D65787400 cmp eax, 'ext' ; vga=ext
2041 00000AB8 7410 je vc0
2042 00000ABA BBFDFF mov bx,-3
2043 00000ABD 663D61736B00 cmp eax, 'ask' ; vga=ask
2044 00000AC3 7405 je vc0
2045 00000AC5 E8AC0A call parseint ; vga=<number>
2046 00000AC8 72C6 jc skip_this_opt ; Not an integer
2047 00000ACA 891EFA01 vc0: mov [bs_vidmode],bx ; Set video mode
2048 00000ACE EBC0 jmp short skip_this_opt
2049 is_mem_cmd:
2050 00000AD0 83C604 add si,byte 4
2051 00000AD3 E89E0A call parseint
2052 00000AD6 72B8 jc skip_this_opt ; Not an integer
2053 00000AD8 2E66891EDC54 mov [cs:HighMemSize],ebx
2054 00000ADE EBB0 jmp short skip_this_opt
2055 cmdline_end:
2056 00000AE0 0E push cs ; Restore standard DS
2057 00000AE1 1F pop ds
2058 00000AE2 81EE0090 sub si,cmd_line_here
2059 00000AE6 89363255 mov [CmdLineLen],si ; Length including final null
2060 ;
2061 ; Now check if we have a large kernel, which needs to be loaded high
2062 ;
2063 00000AEA 66C706E054FFFFFF37 mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
2064 00000AF3 2666813E0202486472- cmp dword [es:su_header],HEADER_ID ; New setup code ID
2065 00000AFC 53
2066 00000AFD 0F855102 jne near old_kernel ; Old kernel, load low
2067 00000B01 26813E06020002 cmp word [es:su_version],0200h ; Setup code version 2.0
2068 00000B08 0F824602 jb near old_kernel ; Old kernel, load low
2069 00000B0C 26813E06020102 cmp word [es:su_version],0201h ; Version 2.01+?
2070 00000B13 721F jb new_kernel ; If 2.00, skip this step
2071 00000B15 26C7062402F48F mov word [es:su_heapend],linux_stack ; Set up the heap
2072 00000B1C 26800E110280 or byte [es:su_loadflags],80h ; Let the kernel know we care
2073 00000B22 26813E06020302 cmp word [es:su_version],0203h ; Version 2.03+?
2074 00000B29 7209 jb new_kernel ; Not 2.03+
2075 00000B2B 2666A12C02 mov eax,[es:su_ramdisk_max]
2076 00000B30 66A3E054 mov [RamdiskMax],eax ; Set the ramdisk limit
2077
2078 ;
2079 ; We definitely have a new-style kernel. Let the kernel know who we are,
2080 ; and that we are clueful
2081 ;
2082 new_kernel:
2083 00000B34 26C606100231 mov byte [es:su_loader],syslinux_id ; Show some ID
2084 00000B3A 260FB606F101 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
2085 00000B40 A32C55 mov [SetupSecs],ax
2086 ;
2087 ; Now see if we have an initial RAMdisk; if so, do requisite computation
2088 ;
2089 00000B43 F606[581D]01 test byte [initrd_flag],1
2090 00000B48 747A jz nk_noinitrd
2091 00000B4A 06 push es ; ES->real_mode_seg
2092 00000B4B 1E push ds
2093 00000B4C 07 pop es ; We need ES==DS
2094 00000B4D BE5655 mov si,InitRD
2095 00000B50 BF6E55 mov di,InitRDCName
2096 00000B53 E84E0B call unmangle_name ; Create human-readable name
2097 00000B56 81EF6E55 sub di,InitRDCName
2098 00000B5A 893E2855 mov [InitRDCNameLen],di
2099 00000B5E BF5655 mov di,InitRD
2100 00000B61 E84C05 call searchdir ; Look for it in directory
2101 00000B64 07 pop es
2102 00000B65 7445 jz initrd_notthere
2103 00000B67 8936[581D] mov [initrd_ptr],si ; Save cluster pointer
2104 00000B6B 26A31C02 mov [es:su_ramdisklen1],ax ; Ram disk length
2105 00000B6F 2689161E02 mov [es:su_ramdisklen2],dx
2106 00000B74 F7360A55 div word [ClustSize]
2107 00000B78 21D2 and dx,dx ; Round up
2108 00000B7A 0F95C2 setnz dl
2109 00000B7D 0FB6D2 movzx dx,dl
2110 00000B80 01D0 add ax,dx
2111 00000B82 A31A55 mov [InitRDClust],ax ; Ramdisk clusters
2112 00000B85 668B16DC54 mov edx,[HighMemSize] ; End of memory
2113 00000B8A 664A dec edx
2114 00000B8C 66A1E054 mov eax,[RamdiskMax] ; Highest address allowed by kernel
2115 00000B90 6639C2 cmp edx,eax
2116 00000B93 7603 jna memsize_ok
2117 00000B95 6689C2 mov edx,eax ; Adjust to fit inside limit
2118 memsize_ok:
2119 00000B98 6642 inc edx
2120 00000B9A 26662B161C02 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk
2121 00000BA0 31D2 xor dx,dx ; Round down to 64K boundary
2122 00000BA2 668916D454 mov [InitRDat],edx ; Load address
2123 00000BA7 E86104 call loadinitrd ; Load initial ramdisk
2124 00000BAA EB18 jmp short initrd_end
2125
2126 initrd_notthere:
2127 00000BAC BE[7B1B] mov si,err_noinitrd
2128 00000BAF E82A08 call cwritestr
2129 00000BB2 BE6E55 mov si,InitRDCName
2130 00000BB5 E82408 call cwritestr
2131 00000BB8 BE[F81C] mov si,crlf_msg
2132 00000BBB E9DD04 jmp abort_load
2133
2134 00000BBE BE[9C1B] no_high_mem: mov si,err_nohighmem ; Error routine
2135 00000BC1 E9D704 jmp abort_load
2136 ;
2137 ; About to load the kernel. This is a modern kernel, so use the boot flags
2138 ; we were provided.
2139 ;
2140 nk_noinitrd:
2141 initrd_end:
2142 00000BC4 26A01102 mov al,[es:su_loadflags]
2143 00000BC8 A24755 mov [LoadFlags],al
2144 ;
2145 ; Load the kernel. We always load it at 100000h even if we're supposed to
2146 ; load it "low"; for a "low" load we copy it down to low memory right before
2147 ; jumping to it.
2148 ;
2149 read_kernel:
2150 00000BCB BE6155 mov si,KernelCName ; Print kernel name part of
2151 00000BCE E80B08 call cwritestr ; "Loading" message
2152 00000BD1 BE[EC1C] mov si,dotdot_msg ; Print dots
2153 00000BD4 E80508 call cwritestr
2154
2155 00000BD7 66A1DC54 mov eax,[HighMemSize]
2156 00000BDB 662D00001000 sub eax,100000h ; Load address
2157 00000BE1 663B06E454 cmp eax,[KernelSize]
2158 00000BE6 72D6 jb no_high_mem ; Not enough high memory
2159 ;
2160 ; Move the stuff beyond the setup code to high memory at 100000h
2161 ;
2162 00000BE8 660FB7362C55 movzx esi,word [SetupSecs] ; Setup sectors
2163 00000BEE 6646 inc esi ; plus 1 boot sector
2164 00000BF0 66C1E609 shl esi,9 ; Convert to bytes
2165 00000BF4 66B900801000 mov ecx,108000h ; 108000h = 1M + 32K
2166 00000BFA 6629F1 sub ecx,esi ; Adjust pointer to 2nd block
2167 00000BFD 66890ED854 mov [HiLoadAddr],ecx
2168 00000C02 6681E900001000 sub ecx,100000h ; Turn into a counter
2169 00000C09 66C1E902 shr ecx,2 ; Convert to dwords
2170 00000C0D 6681C600000700 add esi,(real_mode_seg << 4) ; Pointer to source
2171 00000C14 66BF00001000 mov edi,100000h ; Copy to address 100000h
2172 00000C1A E88B02 call bcopy ; Transfer to high memory
2173
2174 00000C1D 680030 push word xfer_buf_seg ; Transfer buffer segment
2175 00000C20 07 pop es
2176 high_load_loop:
2177 00000C21 BE[ED1C] mov si,dot_msg ; Progress report
2178 00000C24 E8B507 call cwritestr
2179 00000C27 E85D04 call abort_check
2180 00000C2A 8B0E1855 mov cx,[KernelClust]
2181 00000C2E 21C9 and cx,cx
2182 00000C30 743B jz high_load_done ; Zero left (tiny kernel?)
2183 00000C32 3B0E1C55 cmp cx,[ClustPerMoby]
2184 00000C36 7604 jna high_last_moby
2185 00000C38 8B0E1C55 mov cx,[ClustPerMoby]
2186 high_last_moby:
2187 00000C3C 290E1855 sub [KernelClust],cx
2188 00000C40 31DB xor bx,bx ; Load at offset 0
2189 00000C42 5E pop si ; Restore cluster pointer
2190 00000C43 E8E0F6 call getfssec
2191 00000C46 56 push si ; Save cluster pointer
2192 00000C47 9C pushf ; Save EOF
2193 00000C48 31DB xor bx,bx
2194 00000C4A 66BE00000300 mov esi,(xfer_buf_seg << 4)
2195 00000C50 668B3ED854 mov edi,[HiLoadAddr] ; Destination address
2196 00000C55 66B900400000 mov ecx,4000h ; Cheating - transfer 64K
2197 00000C5B E84A02 call bcopy ; Transfer to high memory
2198 00000C5E 66893ED854 mov [HiLoadAddr],edi ; Point to next target area
2199 00000C63 9D popf ; Restore EOF
2200 00000C64 7207 jc high_load_done ; If EOF we are done
2201 00000C66 833E185500 cmp word [KernelClust],byte 0 ; Are we done?
2202 00000C6B 75B4 jne high_load_loop ; Apparently not
2203 high_load_done:
2204 00000C6D 5E pop si ; No longer needed
2205 00000C6E B80070 mov ax,real_mode_seg ; Set to real mode seg
2206 00000C71 8EC0 mov es,ax
2207
2208 00000C73 BE[ED1C] mov si,dot_msg
2209 00000C76 E86307 call cwritestr
2210 ;
2211 ; Abandon hope, ye that enter here! We do no longer permit aborts.
2212 ;
2213 00000C79 E80B04 call abort_check ; Last chance!!
2214
2215 00000C7C BE[D91C] mov si,ready_msg
2216 00000C7F E85A07 call cwritestr
2217
2218 00000C82 E8F00B call vgaclearmode ; We can't trust ourselves after this
2219 ;
2220 ; Now, if we were supposed to load "low", copy the kernel down to 10000h
2221 ; and the real mode stuff to 90000h. We assume that all bzImage kernels are
2222 ; capable of starting their setup from a different address.
2223 ;
2224 00000C85 BB0070 mov bx,real_mode_seg ; Real mode segment
2225 00000C88 8EE3 mov fs,bx ; FS -> real_mode_seg
2226 ;
2227 ; Copy command line. Unfortunately, the kernel boot protocol requires
2228 ; the command line to exist in the 9xxxxh range even if the rest of the
2229 ; setup doesn't.
2230 ;
2231 00000C8A FA cli ; In case of hooked interrupts
2232 00000C8B F606475501 test byte [LoadFlags],LOAD_HIGH
2233 00000C90 7415 jz need_high_cmdline
2234 00000C92 64813E06020202 cmp word [fs:su_version],0202h ; Support new cmdline protocol?
2235 00000C99 720C jb need_high_cmdline
2236 ; New cmdline protocol
2237 ; Store 32-bit (flat) pointer to command line
2238 00000C9B 6466C7062802009007- mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
2239 00000CA4 00
2240 00000CA5 EB7D jmp short in_proper_place
2241
2242 need_high_cmdline:
2243 ;
2244 ; Copy command line up to 90000h
2245 ;
2246 00000CA7 B80090 mov ax,9000h
2247 00000CAA 8EC0 mov es,ax
2248 00000CAC BE0090 mov si,cmd_line_here
2249 00000CAF 89F7 mov di,si
2250 00000CB1 64C70620003FA3 mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
2251 00000CB8 64893E2200 mov [fs:kern_cmd_offset],di ; Store pointer
2252
2253 00000CBD 8B0E3255 mov cx,[CmdLineLen]
2254 00000CC1 83C103 add cx,byte 3
2255 00000CC4 C1E902 shr cx,2 ; Convert to dwords
2256 00000CC7 64F366A5 fs rep movsd
2257
2258 00000CCB F606475501 test byte [LoadFlags],LOAD_HIGH
2259 ; Note bx -> real_mode_seg still
2260 00000CD0 7552 jnz in_proper_place ; If high load, we're done
2261
2262 ;
2263 ; Loading low; we can't assume it's safe to run in place.
2264 ;
2265 ; Copy real_mode stuff up to 90000h
2266 ;
2267 00000CD2 B80070 mov ax,real_mode_seg
2268 00000CD5 8EE0 mov fs,ax
2269 00000CD7 B80090 mov ax,9000h
2270 00000CDA 8EC0 mov es,ax
2271 00000CDC 8B0E2C55 mov cx,[SetupSecs]
2272 00000CE0 41 inc cx ; Setup + boot sector
2273 00000CE1 C1E107 shl cx,7 ; Sectors -> dwords
2274 00000CE4 31F6 xor si,si
2275 00000CE6 31FF xor di,di
2276 00000CE8 64F366A5 fs rep movsd ; Copy setup + boot sector
2277 ;
2278 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
2279 ; setup sectors, but the boot protocol had not yet been defined. They
2280 ; rely on a signature to figure out if they need to copy stuff from
2281 ; the "protected mode" kernel area. Unfortunately, we used that area
2282 ; as a transfer buffer, so it's going to find the signature there.
2283 ; Hence, zero the low 32K beyond the setup area.
2284 ;
2285 00000CEC 8B3E2C55 mov di,[SetupSecs]
2286 00000CF0 47 inc di ; Setup + boot sector
2287 00000CF1 B94000 mov cx,32768/512 ; Sectors/32K
2288 00000CF4 29F9 sub cx,di ; Remaining sectors
2289 00000CF6 C1E709 shl di,9 ; Sectors -> bytes
2290 00000CF9 C1E107 shl cx,7 ; Sectors -> dwords
2291 00000CFC 6631C0 xor eax,eax
2292 00000CFF F366AB rep stosd ; Clear region
2293 ;
2294 00000D02 668B0EE454 mov ecx,[KernelSize]
2295 00000D07 6681C103000000 add ecx,3 ; Round upwards
2296 00000D0E 66C1E902 shr ecx,2 ; Bytes -> dwords
2297 00000D12 66BE00001000 mov esi,100000h
2298 00000D18 66BF00000100 mov edi,10000h
2299 00000D1E E88701 call bcopy
2300
2301 00000D21 BB0090 mov bx,9000h ; Real mode segment
2302
2303 ;
2304 ; Now everything is where it needs to be...
2305 ;
2306 in_proper_place:
2307 00000D24 8EC3 mov es,bx ; Real mode segment
2308 ;
2309 ; If the default root device is set to FLOPPY (0000h), change to
2310 ; /dev/fd0 (0200h)
2311 ;
2312 00000D26 26833EFC0100 cmp word [es:bs_rootdev],byte 0
2313 00000D2C 7507 jne root_not_floppy
2314 00000D2E 26C706FC010002 mov word [es:bs_rootdev],0200h
2315 root_not_floppy:
2316 ;
2317 ; Copy the disk table to high memory, then re-initialize the floppy
2318 ; controller
2319 ;
2320 ; This needs to be moved before the copy
2321 ;
2322 %if 0
2323 push ds
2324 push bx
2325 lds si,[fdctab]
2326 mov di,linux_fdctab
2327 mov cx,3 ; 12 bytes
2328 push di
2329 rep movsd
2330 pop di
2331 mov [fdctab1],di ; Save new floppy tab pos
2332 mov [fdctab2],es
2333 xor ax,ax
2334 xor dx,dx
2335 int 13h
2336 pop bx
2337 pop ds
2338 %endif
2339 ;
2340 ; Linux wants the floppy motor shut off before starting the kernel,
2341 ; at least bootsect.S seems to imply so
2342 ;
2343 kill_motor:
2344 00000D35 BAF203 mov dx,03F2h
2345 00000D38 30C0 xor al,al
2346 00000D3A E8C001 call slow_out
2347 ;
2348 ; If we're debugging, wait for a keypress so we can read any debug messages
2349 ;
2350 %ifdef debug
2351 xor ax,ax
2352 int 16h
2353 %endif
2354 ;
2355 ; Set up segment registers and the Linux real-mode stack
2356 ; Note: bx == the real mode segment
2357 ;
2358 00000D3D FA cli
2359 ; es is already == real mode segment
2360 00000D3E 8EDB mov ds,bx
2361 00000D40 8EE3 mov fs,bx
2362 00000D42 8EEB mov gs,bx
2363 00000D44 8ED3 mov ss,bx
2364 00000D46 BCF48F mov sp,linux_stack
2365 ;
2366 ; We're done... now RUN THAT KERNEL!!!!
2367 ; Setup segment == real mode segment + 020h; we need to jump to offset
2368 ; zero in the real mode segment.
2369 ;
2370 00000D49 81C32000 add bx,020h
2371 00000D4D 53 push bx
2372 00000D4E 680000 push word 0h
2373 00000D51 CB retf
2374
2375 ;
2376 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have
2377 ; initrd, and are always loaded low.
2378 ;
2379 old_kernel:
2380 00000D52 F606[581D]01 test byte [initrd_flag],1 ; Old kernel can't have initrd
2381 00000D57 7406 jz load_old_kernel
2382 00000D59 BE[E71B] mov si,err_oldkernel
2383 00000D5C E93C03 jmp abort_load
2384 load_old_kernel:
2385 00000D5F C7062C550400 mov word [SetupSecs],4 ; Always 4 setup sectors
2386 00000D65 C606475500 mov byte [LoadFlags],0 ; Always low
2387 00000D6A E95EFE jmp read_kernel
2388
2389 ;
2390 ; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file,
2391 ; except that it may, of course, not contain any DOS system calls. We
2392 ; do, however, allow the execution of INT 20h to return to SYSLINUX.
2393 ;
2394 is_comboot_image:
2395 00000D6D 21D2 and dx,dx
2396 00000D6F 7578 jnz comboot_too_large
2397 00000D71 3D00FF cmp ax,0ff00h ; Max size in bytes
2398 00000D74 7373 jae comboot_too_large
2399
2400 ;
2401 ; Set up the DOS vectors in the IVT (INT 20h-3fh)
2402 ;
2403 00000D76 66C7068000- mov dword [4*0x20],comboot_return ; INT 20h vector
2404 00000D7B [F20D0000]
2405 00000D7F 66B8[040E0000] mov eax,comboot_bogus
2406 00000D85 BF8400 mov di,4*0x21
2407 00000D88 B91F00 mov cx,31 ; All remaining DOS vectors
2408 00000D8B F366AB rep stosd
2409
2410 00000D8E B90020 mov cx,comboot_seg
2411 00000D91 8EC1 mov es,cx
2412
2413 00000D93 BB0001 mov bx,100h ; Load at <seg>:0100h
2414
2415 00000D96 8B0E1C55 mov cx,[ClustPerMoby] ; Absolute maximum # of clusters
2416 00000D9A E889F5 call getfssec
2417
2418 00000D9D 31FF xor di,di
2419 00000D9F B94000 mov cx,64 ; 256 bytes (size of PSP)
2420 00000DA2 6631C0 xor eax,eax ; Clear PSP
2421 00000DA5 F366AB rep stosd
2422
2423 00000DA8 26C7060000CD20 mov word [es:0], 020CDh ; INT 20h instruction
2424 ; First non-free paragraph
2425 00000DAF 26C70602000030 mov word [es:02h], comboot_seg+1000h
2426
2427 ; Copy the command line from high memory
2428 00000DB6 B97D00 mov cx,125 ; Max cmdline len (minus space and CR)
2429 00000DB9 8B362455 mov si,[CmdOptPtr]
2430 00000DBD BF8100 mov di,081h ; Offset in PSP for command line
2431 00000DC0 B020 mov al,' ' ; DOS command lines begin with a space
2432 00000DC2 AA stosb
2433
2434 00000DC3 AC comboot_cmd_cp: lodsb
2435 00000DC4 20C0 and al,al
2436 00000DC6 7403 jz comboot_end_cmd
2437 00000DC8 AA stosb
2438 00000DC9 E2F8 loop comboot_cmd_cp
2439 00000DCB B00D comboot_end_cmd: mov al,0Dh ; CR after last character
2440 00000DCD AA stosb
2441 00000DCE B07E mov al,126 ; Include space but not CR
2442 00000DD0 28C8 sub al,cl
2443 00000DD2 26A28000 mov [es:80h], al ; Store command line length
2444
2445 00000DD6 E89C0A call vgaclearmode ; Reset video
2446
2447 00000DD9 8CC0 mov ax,es
2448 00000DDB 8ED8 mov ds,ax
2449 00000DDD 8ED0 mov ss,ax
2450 00000DDF 31E4 xor sp,sp
2451 00000DE1 680000 push word 0 ; Return to address 0 -> exit
2452
2453 00000DE4 EA00010020 jmp comboot_seg:100h ; Run it
2454
2455 ; Looks like a COMBOOT image but too large
2456 comboot_too_large:
2457 00000DE9 BE[371C] mov si,err_comlarge
2458 00000DEC E8ED05 call cwritestr
2459 00000DEF E9DEF8 cb_enter: jmp enter_command
2460
2461 ; Proper return vector
2462 00000DF2 FA comboot_return: cli ; Don't trust anyone
2463 00000DF3 31C0 xor ax,ax
2464 00000DF5 8ED0 mov ss,ax
2465 00000DF7 368B262E55 mov sp,[ss:SavedSP]
2466 00000DFC 8ED8 mov ds,ax
2467 00000DFE 8EC0 mov es,ax
2468 00000E00 FB sti
2469 00000E01 FC cld
2470 00000E02 EBEB jmp short cb_enter
2471
2472 ; Attempted to execute DOS system call
2473 00000E04 FA comboot_bogus: cli ; Don't trust anyone
2474 00000E05 31C0 xor ax,ax
2475 00000E07 8ED0 mov ss,ax
2476 00000E09 368B262E55 mov sp,[ss:SavedSP]
2477 00000E0E 8ED8 mov ds,ax
2478 00000E10 8EC0 mov es,ax
2479 00000E12 FB sti
2480 00000E13 FC cld
2481 00000E14 BE6155 mov si,KernelCName
2482 00000E17 E8C205 call cwritestr
2483 00000E1A BE[191C] mov si,err_notdos
2484 00000E1D E8BC05 call cwritestr
2485 00000E20 EBCD jmp short cb_enter
2486
2487 ;
2488 ; Load a boot sector
2489 ;
2490 is_bootsector:
2491 ; Transfer zero bytes
2492 00000E22 680000 push word 0
2493 00000E25 EB03 jmp short load_bootsec
2494 is_bss_sector:
2495 ; Transfer the superblock
2496 00000E27 683300 push word superblock_len
2497 load_bootsec:
2498 00000E2A 21D2 and dx,dx
2499 00000E2C 754F jnz bad_bootsec
2500 00000E2E 8B1E[0B00] mov bx,[bsBytesPerSec]
2501 00000E32 39D8 cmp ax,bx
2502 00000E34 7547 jne bad_bootsec
2503
2504 ; Make sure we don't test this uninitialized
2505 00000E36 8997FE0F mov [bx+trackbuf-2],dx ; Note DX == 0
2506
2507 00000E3A BB0010 mov bx,trackbuf
2508 00000E3D B90100 mov cx,1 ; 1 cluster >= 1 sector
2509 00000E40 E8E3F4 call getfssec
2510
2511 00000E43 8B1E[0B00] mov bx,[bsBytesPerSec]
2512 00000E47 8B87FE0F mov ax,[bx+trackbuf-2]
2513 00000E4B 3D55AA cmp ax,0AA55h ; Boot sector signature
2514 00000E4E 752D jne bad_bootsec
2515
2516 00000E50 BE[0B00] mov si,superblock
2517 00000E53 BF0B10 mov di,trackbuf+(superblock-bootsec)
2518 00000E56 59 pop cx ; Transfer count
2519 00000E57 F3A4 rep movsb
2520 ;
2521 ; Okay, here we go... copy over our own boot sector and run the new one
2522 ;
2523 00000E59 E8190A call vgaclearmode ; Reset video
2524
2525 00000E5C FA cli ; Point of no return
2526
2527 00000E5D 8A16[2400] mov dl,[bsDriveNumber] ; May not be in new bootsector!
2528
2529 00000E61 BE0010 mov si,trackbuf
2530 00000E64 BF[0000] mov di,bootsec
2531 00000E67 8B0E[0B00] mov cx,[bsBytesPerSec]
2532 00000E6B F3A4 rep movsb ; Copy the boot sector!
2533
2534 00000E6D BEB054 mov si,PartInfo
2535 00000E70 BFEE07 mov di,800h-18 ; Put partition info here
2536 00000E73 57 push di
2537 00000E74 B90800 mov cx,8 ; 16 bytes
2538 00000E77 F3A5 rep movsw
2539 00000E79 5E pop si ; DS:SI points to partition info
2540
2541 00000E7A E983F1 jmp bootsec
2542
2543 bad_bootsec:
2544 00000E7D BE[521C] mov si,err_bootsec
2545 00000E80 E85905 call cwritestr
2546 00000E83 E94AF8 jmp enter_command
2547
2548 ;
2549 ; 32-bit bcopy routine for real mode
2550 ;
2551 ; We enter protected mode, set up a flat 32-bit environment, run rep movsd
2552 ; and then exit. IMPORTANT: This code assumes cs == ss == 0.
2553 ;
2554 ; This code is probably excessively anal-retentive in its handling of
2555 ; segments, but this stuff is painful enough as it is without having to rely
2556 ; on everything happening "as it ought to."
2557 ;
2558 00000E86 90<rept> align 4
2559 00000E88 1F00 bcopy_gdt: dw bcopy_gdt_size-1 ; Null descriptor - contains GDT
2560 00000E8A [880E0000] dd bcopy_gdt ; pointer for LGDT instruction
2561 00000E8E 0000 dw 0
2562 00000E90 FFFF0000 dd 0000ffffh ; Code segment, use16, readable,
2563 00000E94 009B0000 dd 00009b00h ; present, dpl 0, cover 64K
2564 00000E98 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write,
2565 00000E9C 00938F00 dd 008f9300h ; present, dpl 0, cover all 4G
2566 00000EA0 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write,
2567 00000EA4 00930000 dd 00009300h ; present, dpl 0, cover 64K
2568 bcopy_gdt_size: equ $-bcopy_gdt
2569
2570 00000EA8 6650 bcopy: push eax
2571 00000EAA 9C pushf ; Saves, among others, the IF flag
2572 00000EAB 0FA8 push gs
2573 00000EAD 0FA0 push fs
2574 00000EAF 1E push ds
2575 00000EB0 06 push es
2576
2577 00000EB1 FA cli
2578 00000EB2 E84E00 call enable_a20
2579
2580 00000EB5 660F0116[880E] o32 lgdt [bcopy_gdt]
2581 00000EBB 0F20C0 mov eax,cr0
2582 00000EBE 0C01 or al,1
2583 00000EC0 0F22C0 mov cr0,eax ; Enter protected mode
2584 00000EC3 EA[C80E]0800 jmp 08h:.in_pm
2585
2586 00000EC8 B81000 .in_pm: mov ax,10h ; Data segment selector
2587 00000ECB 8EC0 mov es,ax
2588 00000ECD 8ED8 mov ds,ax
2589
2590 00000ECF B018 mov al,18h ; "Real-mode-like" data segment
2591 00000ED1 8ED0 mov ss,ax
2592 00000ED3 8EE0 mov fs,ax
2593 00000ED5 8EE8 mov gs,ax
2594
2595 00000ED7 67F366A5 a32 rep movsd ; Do our business
2596
2597 00000EDB 8EC0 mov es,ax ; Set to "real-mode-like"
2598 00000EDD 8ED8 mov ds,ax
2599
2600 00000EDF 0F20C0 mov eax,cr0
2601 00000EE2 24FE and al,~1
2602 00000EE4 0F22C0 mov cr0,eax ; Disable protected mode
2603 00000EE7 EA[EC0E]0000 jmp 0:.in_rm
2604
2605 00000EEC 31C0 .in_rm: xor ax,ax ; Back in real mode
2606 00000EEE 8ED0 mov ss,ax
2607 00000EF0 07 pop es
2608 00000EF1 1F pop ds
2609 00000EF2 0FA1 pop fs
2610 00000EF4 0FA9 pop gs
2611 00000EF6 E8AD00 call disable_a20
2612
2613 00000EF9 9D popf ; Re-enables interrupts
2614 00000EFA 6658 pop eax
2615 00000EFC C3 ret
2616
2617 ;
2618 ; Routines to enable and disable (yuck) A20. These routines are gathered
2619 ; from tips from a couple of sources, including the Linux kernel and
2620 ; http://www.x86.org/. The need for the delay to be as large as given here
2621 ; is indicated by Donnie Barnes of RedHat, the problematic system being an
2622 ; IBM ThinkPad 760EL.
2623 ;
2624 ; We typically toggle A20 twice for every 64K transferred.
2625 ;
2626 %define io_delay call _io_delay
2627 %define IO_DELAY_PORT 80h ; Invalid port (we hope!)
2628 %define disable_wait 32 ; How long to wait for a disable
2629
2630 %define A20_DUNNO 0 ; A20 type unknown
2631 %define A20_NONE 1 ; A20 always on?
2632 %define A20_BIOS 2 ; A20 BIOS enable
2633 %define A20_KBC 3 ; A20 through KBC
2634 %define A20_FAST 4 ; A20 through port 92h
2635
2636 00000EFD EE slow_out: out dx, al ; Fall through
2637
2638 00000EFE E680 _io_delay: out IO_DELAY_PORT,al
2639 00000F00 E680 out IO_DELAY_PORT,al
2640 00000F02 C3 ret
2641
2642 enable_a20:
2643 00000F03 6660 pushad
2644 00000F05 2EC6064855FF mov byte [cs:A20Tries],255 ; Times to try to make this work
2645
2646 try_enable_a20:
2647 ;
2648 ; Flush the caches
2649 ;
2650 ; call try_wbinvd
2651
2652 ;
2653 ; If the A20 type is known, jump straight to type
2654 ;
2655 00000F0B 2E8B2E[761D] mov bp,[cs:A20Type]
2656 00000F10 01ED add bp,bp ; Convert to word offset
2657 00000F12 2EFFA6[621D] jmp word [cs:bp+A20List]
2658
2659 ;
2660 ; First, see if we are on a system with no A20 gate
2661 ;
2662 a20_dunno:
2663 a20_none:
2664 00000F17 2EC606[761D]01 mov byte [cs:A20Type], A20_NONE
2665 00000F1D E86400 call a20_test
2666 00000F20 755F jnz a20_done
2667
2668 ;
2669 ; Next, try the BIOS (INT 15h AX=2401h)
2670 ;
2671 a20_bios:
2672 00000F22 2EC606[761D]02 mov byte [cs:A20Type], A20_BIOS
2673 00000F28 B80124 mov ax,2401h
2674 00000F2B 9C pushf ; Some BIOSes muck with IF
2675 00000F2C CD15 int 15h
2676 00000F2E 9D popf
2677
2678 00000F2F E85200 call a20_test
2679 00000F32 754D jnz a20_done
2680
2681 ;
2682 ; Enable the keyboard controller A20 gate
2683 ;
2684 a20_kbc:
2685 00000F34 B201 mov dl, 1 ; Allow early exit
2686 00000F36 E8AE00 call empty_8042
2687 00000F39 7546 jnz a20_done ; A20 live, no need to use KBC
2688
2689 00000F3B 2EC606[761D]03 mov byte [cs:A20Type], A20_KBC ; Starting KBC command sequence
2690
2691 00000F41 B0D1 mov al,0D1h ; Command write
2692 00000F43 E664 out 064h, al
2693 00000F45 E89D00 call empty_8042_uncond
2694
2695 00000F48 B0DF mov al,0DFh ; A20 on
2696 00000F4A E660 out 060h, al
2697 00000F4C E89600 call empty_8042_uncond
2698
2699 ; Verify that A20 actually is enabled. Do that by
2700 ; observing a word in low memory and the same word in
2701 ; the HMA until they are no longer coherent. Note that
2702 ; we don't do the same check in the disable case, because
2703 ; we don't want to *require* A20 masking (SYSLINUX should
2704 ; work fine without it, if the BIOS does.)
2705 00000F4F 51 .kbc_wait: push cx
2706 00000F50 31C9 xor cx,cx
2707 .kbc_wait_loop:
2708 00000F52 E82F00 call a20_test
2709 00000F55 7529 jnz a20_done_pop
2710 00000F57 E2F9 loop .kbc_wait_loop
2711
2712 00000F59 59 pop cx
2713 ;
2714 ; Running out of options here. Final attempt: enable the "fast A20 gate"
2715 ;
2716 a20_fast:
2717 00000F5A 2EC606[761D]04 mov byte [cs:A20Type], A20_FAST ; Haven't used the KBC yet
2718 00000F60 E492 in al, 092h
2719 00000F62 0C02 or al,02h
2720 00000F64 24FE and al,~01h ; Don't accidentally reset the machine!
2721 00000F66 E692 out 092h, al
2722
2723 00000F68 51 .fast_wait: push cx
2724 00000F69 31C9 xor cx,cx
2725 .fast_wait_loop:
2726 00000F6B E81600 call a20_test
2727 00000F6E 7510 jnz a20_done_pop
2728 00000F70 E2F9 loop .fast_wait_loop
2729
2730 00000F72 59 pop cx
2731
2732 ;
2733 ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
2734 ; and report failure to the user.
2735 ;
2736
2737
2738 00000F73 2EFE0E4855 dec byte [cs:A20Tries]
2739 00000F78 7591 jnz try_enable_a20
2740
2741 00000F7A BE[7A1C] mov si, err_a20
2742 00000F7D E91B01 jmp abort_load
2743 ;
2744 ; A20 unmasked, proceed...
2745 ;
2746 00000F80 59 a20_done_pop: pop cx
2747 00000F81 6661 a20_done: popad
2748 00000F83 C3 ret
2749
2750 ;
2751 ; This routine tests if A20 is enabled (ZF = 0). This routine
2752 ; must not destroy any register contents.
2753 ;
2754 a20_test:
2755 00000F84 06 push es
2756 00000F85 51 push cx
2757 00000F86 50 push ax
2758 00000F87 B9FFFF mov cx,0FFFFh ; HMA = segment 0FFFFh
2759 00000F8A 8EC1 mov es,cx
2760 00000F8C B92000 mov cx,32 ; Loop count
2761 00000F8F 2EA13055 mov ax,[cs:A20Test]
2762 00000F93 40 .a20_wait: inc ax
2763 00000F94 2EA33055 mov [cs:A20Test],ax
2764 00000F98 E863FF io_delay ; Serialize, and fix delay
2765 00000F9B 263B064055 cmp ax,[es:A20Test+10h]
2766 00000FA0 E1F1 loopz .a20_wait
2767 00000FA2 58 .a20_done: pop ax
2768 00000FA3 59 pop cx
2769 00000FA4 07 pop es
2770 00000FA5 C3 ret
2771
2772 disable_a20:
2773 00000FA6 6660 pushad
2774 ;
2775 ; Flush the caches
2776 ;
2777 ; call try_wbinvd
2778
2779 00000FA8 2E8B2E[761D] mov bp,[cs:A20Type]
2780 00000FAD 01ED add bp,bp ; Convert to word offset
2781 00000FAF 2EFFA6[6C1D] jmp word [cs:bp+A20DList]
2782
2783 a20d_bios:
2784 00000FB4 B80024 mov ax,2400h
2785 00000FB7 9C pushf ; Some BIOSes muck with IF
2786 00000FB8 CD15 int 15h
2787 00000FBA 9D popf
2788 00000FBB EB19 jmp short a20d_snooze
2789
2790 ;
2791 ; Disable the "fast A20 gate"
2792 ;
2793 a20d_fast:
2794 00000FBD E492 in al, 092h
2795 00000FBF 24FC and al,~03h
2796 00000FC1 E692 out 092h, al
2797 00000FC3 EB11 jmp short a20d_snooze
2798
2799 ;
2800 ; Disable the keyboard controller A20 gate
2801 ;
2802 a20d_kbc:
2803 00000FC5 E81D00 call empty_8042_uncond
2804 00000FC8 B0D1 mov al,0D1h
2805 00000FCA E664 out 064h, al ; Command write
2806 00000FCC E81600 call empty_8042_uncond
2807 00000FCF B0DD mov al,0DDh ; A20 off
2808 00000FD1 E660 out 060h, al
2809 00000FD3 E80F00 call empty_8042_uncond
2810 ; Wait a bit for it to take effect
2811 a20d_snooze:
2812 00000FD6 51 push cx
2813 00000FD7 B92000 mov cx, disable_wait
2814 00000FDA E8A7FF .delayloop: call a20_test
2815 00000FDD 7402 jz .disabled
2816 00000FDF E2F9 loop .delayloop
2817 00000FE1 59 .disabled: pop cx
2818 a20d_dunno:
2819 a20d_none:
2820 00000FE2 6661 popad
2821 00000FE4 C3 ret
2822
2823 ;
2824 ; Routine to empty the 8042 KBC controller. If dl != 0
2825 ; then we will test A20 in the loop and exit if A20 is
2826 ; suddenly enabled.
2827 ;
2828 empty_8042_uncond:
2829 00000FE5 30D2 xor dl,dl
2830 empty_8042:
2831 00000FE7 E89AFF call a20_test
2832 00000FEA 7404 jz .a20_on
2833 00000FEC 20D2 and dl,dl
2834 00000FEE 7517 jnz .done
2835 00000FF0 E80BFF .a20_on: io_delay
2836 00000FF3 E464 in al, 064h ; Status port
2837 00000FF5 A801 test al,1
2838 00000FF7 7407 jz .no_output
2839 00000FF9 E802FF io_delay
2840 00000FFC E460 in al, 060h ; Read input
2841 00000FFE EBE7 jmp short empty_8042
2842 .no_output:
2843 00001000 A802 test al,2
2844 00001002 75E3 jnz empty_8042
2845 00001004 E8F7FE io_delay
2846 00001007 C3 .done: ret
2847
2848 ;
2849 ; WBINVD instruction; gets auto-eliminated on 386 CPUs
2850 ;
2851 try_wbinvd:
2852 00001008 0F09 wbinvd
2853 0000100A C3 ret
2854
2855 ;
2856 ; Load RAM disk into high memory
2857 ;
2858 loadinitrd:
2859 0000100B 06 push es ; Save ES on entry
2860 0000100C B80070 mov ax,real_mode_seg
2861 0000100F 8EC0 mov es,ax
2862 00001011 8B36[581D] mov si,[initrd_ptr]
2863 00001015 668B3ED454 mov edi,[InitRDat] ; initrd load address
2864 0000101A 2666893E1802 mov [es:su_ramdiskat],edi ; Offset for ram disk
2865 00001020 56 push si
2866 00001021 BE6E55 mov si,InitRDCName ; Write ramdisk name
2867 00001024 E8B503 call cwritestr
2868 00001027 BE[EC1C] mov si,dotdot_msg ; Write dots
2869 0000102A E8AF03 call cwritestr
2870 rd_load_loop:
2871 0000102D BE[ED1C] mov si,dot_msg ; Progress report
2872 00001030 E8A903 call cwritestr
2873 00001033 5E pop si ; Restore cluster pointer
2874 00001034 E85000 call abort_check
2875 00001037 8B0E1A55 mov cx,[InitRDClust]
2876 0000103B 3B0E1C55 cmp cx,[ClustPerMoby]
2877 0000103F 7604 jna rd_last_moby
2878 00001041 8B0E1C55 mov cx,[ClustPerMoby]
2879 rd_last_moby:
2880 00001045 290E1A55 sub [InitRDClust],cx
2881 00001049 31DB xor bx,bx ; Load at offset 0
2882 0000104B 680030 push word xfer_buf_seg ; Bounce buffer segment
2883 0000104E 07 pop es
2884 0000104F 51 push cx
2885 00001050 E8D3F2 call getfssec
2886 00001053 59 pop cx
2887 00001054 56 push si ; Save cluster pointer
2888 00001055 66BE00000300 mov esi,(xfer_buf_seg << 4)
2889 0000105B 668B3ED454 mov edi,[InitRDat]
2890 00001060 66B900400000 mov ecx,4000h ; Copy 64K
2891 00001066 E83FFE call bcopy ; Does not change flags!!
2892 00001069 7210 jc rd_load_done ; EOF?
2893 0000106B 668106D45400000100 add dword [InitRDat],10000h ; Point to next 64K
2894 00001074 833E1A5500 cmp word [InitRDClust],byte 0 ; Are we done?
2895 00001079 75B2 jne rd_load_loop ; Apparently not
2896 rd_load_done:
2897 0000107B 5E pop si ; Clean up the stack
2898 0000107C E85A03 call crlf
2899 0000107F BE[E31C] mov si,loading_msg ; Write new "Loading " for
2900 00001082 E85703 call cwritestr ; the benefit of the kernel
2901 00001085 07 pop es ; Restore original ES
2902 00001086 C3 ret
2903
2904 ;
2905 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
2906 ;
2907 abort_check:
2908 00001087 E86503 call pollchar
2909 0000108A 7423 jz ac_ret1
2910 0000108C 60 pusha
2911 0000108D E88903 call getchar
2912 00001090 3C1B cmp al,27 ; <ESC>
2913 00001092 7404 je ac_kill
2914 00001094 3C03 cmp al,3 ; <Ctrl-C>
2915 00001096 7516 jne ac_ret2
2916 00001098 BE[EF1C] ac_kill: mov si,aborted_msg
2917
2918 ;
2919 ; abort_load: Called by various routines which wants to print a fatal
2920 ; error message and return to the command prompt. Since this
2921 ; may happen at just about any stage of the boot process, assume
2922 ; our state is messed up, and just reset the segment registers
2923 ; and the stack forcibly.
2924 ;
2925 ; SI = offset (in _text) of error message to print
2926 ;
2927 abort_load:
2928 0000109B 8CC8 mov ax,cs ; Restore CS = DS = ES
2929 0000109D 8ED8 mov ds,ax
2930 0000109F 8EC0 mov es,ax
2931 000010A1 FA cli
2932 000010A2 BC[FAFF] mov sp,StackBuf-2*3 ; Reset stack
2933 000010A5 8ED0 mov ss,ax ; Just in case...
2934 000010A7 FB sti
2935 000010A8 E83103 call cwritestr ; Expects SI -> error msg
2936 000010AB E922F6 al_ok: jmp enter_command ; Return to command prompt
2937 ;
2938 ; End of abort_check
2939 ;
2940 000010AE 61 ac_ret2: popa
2941 000010AF C3 ac_ret1: ret
2942
2943 ;
2944 ; searchdir: Search the root directory for a pre-mangled filename in
2945 ; DS:DI. This routine is similar to the one in the boot
2946 ; sector, but is a little less Draconian when it comes to
2947 ; error handling, plus it reads the root directory in
2948 ; larger chunks than a sector at a time (which is probably
2949 ; a waste of coding effort, but I like to do things right).
2950 ;
2951 ; FIXME: usually we can load the entire root dir in memory,
2952 ; and files are usually at the beginning anyway. It probably
2953 ; would be worthwhile to remember if we have the first chunk
2954 ; in memory and skip the load if that (it would speed up online
2955 ; help, mainly.)
2956 ;
2957 ; NOTE: This file considers finding a zero-length file an
2958 ; error. This is so we don't have to deal with that special
2959 ; case elsewhere in the program (most loops have the test
2960 ; at the end).
2961 ;
2962 ; If successful:
2963 ; ZF clear
2964 ; SI = cluster # for the first cluster
2965 ; DX:AX = file length in bytes
2966 ; If unsuccessful
2967 ; ZF set
2968 ;
2969
2970 searchdir:
2971 000010B0 A1[1100] mov ax,[bsRootDirEnts]
2972 000010B3 A30255 mov [DirScanCtr],ax
2973 000010B6 A10055 mov ax,[RootDirSize]
2974 000010B9 A30455 mov [DirBlocksLeft],ax
2975 000010BC A1F454 mov ax,[RootDir1]
2976 000010BF 8B16F654 mov dx,[RootDir2]
2977 scan_group:
2978 000010C3 8B2E0455 mov bp,[DirBlocksLeft]
2979 000010C7 21ED and bp,bp
2980 000010C9 7467 jz dir_return
2981 000010CB 3B2E1255 cmp bp,[BufSafeSec]
2982 000010CF 7604 jna load_last
2983 000010D1 8B2E1255 mov bp,[BufSafeSec]
2984 load_last:
2985 000010D5 292E0455 sub [DirBlocksLeft],bp
2986 000010D9 50 push ax
2987 000010DA 52 push dx
2988 000010DB A1[0B00] mov ax,[bsBytesPerSec]
2989 000010DE F7E5 mul bp
2990 000010E0 05E10F add ax,trackbuf-31
2991 000010E3 A30655 mov [EndofDirSec],ax ; End of loaded
2992 000010E6 5A pop dx
2993 000010E7 58 pop ax
2994 000010E8 55 push bp ; Save number of sectors
2995 000010E9 50 push ax ; Save present location
2996 000010EA 52 push dx
2997 000010EB 57 push di ; Save name
2998 000010EC BB0010 mov bx,trackbuf
2999 000010EF E882F0 call getlinsec
3000 000010F2 5F pop di
3001 000010F3 5A pop dx
3002 000010F4 58 pop ax
3003 000010F5 5D pop bp
3004 000010F6 BE0010 mov si,trackbuf
3005 000010F9 803C00 dir_test_name: cmp byte [si],0 ; Directory high water mark
3006 000010FC 7434 je dir_return ; Failed
3007 000010FE F6440B18 test byte [si+11],18h ; Check it really is a file
3008 00001102 750B jnz dir_not_this
3009 00001104 57 push di
3010 00001105 56 push si
3011 00001106 B90B00 mov cx,11 ; Filename = 11 bytes
3012 00001109 F3A6 repe cmpsb
3013 0000110B 5E pop si
3014 0000110C 5F pop di
3015 0000110D 7416 je dir_success
3016 0000110F 83C620 dir_not_this: add si,byte 32
3017 00001112 FF0E0255 dec word [DirScanCtr]
3018 00001116 741A jz dir_return ; Out of it...
3019 00001118 3B360655 cmp si,[EndofDirSec]
3020 0000111C 72DB jb dir_test_name
3021 0000111E 01E8 add ax,bp ; Increment linear sector number
3022 00001120 83D200 adc dx,byte 0
3023 00001123 EB9E jmp short scan_group
3024 dir_success:
3025 00001125 8B441C mov ax,[si+28] ; Length of file
3026 00001128 8B541E mov dx,[si+30]
3027 0000112B 8B741A mov si,[si+26] ; Cluster pointer
3028 0000112E 89C3 mov bx,ax
3029 00001130 09D3 or bx,dx ; Sets ZF iff DX:AX is zero
3030 dir_return:
3031 00001132 C3 lf_ret: ret
3032
3033 ;
3034 ; loadfont: Load a .psf font file and install it onto the VGA console
3035 ; (if we're not on a VGA screen then ignore.) It is called with
3036 ; SI and DX:AX set by routine searchdir
3037 ;
3038 loadfont:
3039 00001133 BB0010 mov bx,trackbuf ; The trackbuf is >= 16K; the part
3040 00001136 8B0E1055 mov cx,[BufSafe] ; of a PSF file we care about is no
3041 0000113A E8E9F1 call getfssec ; more than 8K+4 bytes
3042
3043 0000113D A10010 mov ax,[trackbuf] ; Magic number
3044 00001140 3D3604 cmp ax,0436h
3045 00001143 75ED jne lf_ret
3046
3047 00001145 A00210 mov al,[trackbuf+2] ; File mode
3048 00001148 3C05 cmp al,5 ; Font modes 0-5 supported
3049 0000114A 77E6 ja lf_ret
3050
3051 0000114C 8A3E0310 mov bh,byte [trackbuf+3] ; Height of font
3052 00001150 80FF02 cmp bh,2 ; VGA minimum
3053 00001153 72DD jb lf_ret
3054 00001155 80FF20 cmp bh,32 ; VGA maximum
3055 00001158 77D8 ja lf_ret
3056
3057 ; Copy to font buffer
3058 0000115A BE0410 mov si,trackbuf+4 ; Start of font data
3059 0000115D 883E[781D] mov [VGAFontSize],bh
3060 00001161 BF00E0 mov di,vgafontbuf
3061 00001164 B90008 mov cx,(32*256) >> 2 ; Maximum size
3062 00001167 F366A5 rep movsd
3063
3064 0000116A C606[7A1D]01 mov [UserFont], byte 1 ; Set font flag
3065
3066 ; Fall through to use_font
3067
3068 ;
3069 ; use_font:
3070 ; This routine activates whatever font happens to be in the
3071 ; vgafontbuf, and updates the adjust_screen data.
3072 ; Must be called with CS = DS = ES
3073 ;
3074 use_font:
3075 0000116F F606[7A1D]01 test [UserFont], byte 1 ; Are we using a user-specified font?
3076 00001174 7441 jz adjust_screen ; If not, just do the normal stuff
3077
3078 00001176 BD00E0 mov bp,vgafontbuf
3079 00001179 8A3E[781D] mov bh,[VGAFontSize]
3080
3081 0000117D 30DB xor bl,bl ; Needed by both INT 10h calls
3082 0000117F 803E[CC18]01 cmp [UsingVGA], byte 1 ; Are we in graphics mode?
3083 00001184 7520 jne .text
3084
3085 .graphics:
3086 00001186 31C9 xor cx,cx
3087 00001188 88F9 mov cl,bh ; CX = bytes/character
3088 0000118A B8E001 mov ax,480
3089 0000118D F6F1 div cl ; Compute char rows per screen
3090 0000118F 88C2 mov dl,al
3091 00001191 FEC8 dec al
3092 00001193 A24155 mov [VidRows],al
3093 00001196 B82111 mov ax,1121h ; Set user character table
3094 00001199 CD10 int 10h
3095 0000119B C60640554F mov [VidCols], byte 79 ; Always 80 bytes/line
3096 000011A0 C6063D5500 mov [TextPage], byte 0 ; Always page 0
3097 000011A5 C3 ret ; No need to call adjust_screen
3098
3099 .text:
3100 000011A6 B90001 mov cx,256
3101 000011A9 31D2 xor dx,dx
3102 000011AB B81011 mov ax,1110h
3103 000011AE CD10 int 10h ; Load into VGA RAM
3104
3105 000011B0 30DB xor bl,bl
3106 000011B2 B80311 mov ax,1103h ; Select page 0
3107 000011B5 CD10 int 10h
3108
3109 ; Fall through to adjust_screen
3110
3111 ;
3112 ; adjust_screen: Set the internal variables associated with the screen size.
3113 ; This is a subroutine in case we're loading a custom font.
3114 ;
3115 adjust_screen:
3116 000011B7 A08404 mov al,[BIOS_vidrows]
3117 000011BA 20C0 and al,al
3118 000011BC 7502 jnz vidrows_is_ok
3119 000011BE B018 mov al,24 ; No vidrows in BIOS, assume 25
3120 ; (Remember: vidrows == rows-1)
3121 000011C0 A24155 vidrows_is_ok: mov [VidRows],al
3122 000011C3 B40F mov ah,0fh
3123 000011C5 CD10 int 10h ; Read video state
3124 000011C7 883E3D55 mov [TextPage],bh
3125 000011CB FECC dec ah ; Store count-1 (same as rows)
3126 000011CD 88264055 mov [VidCols],ah
3127 000011D1 C3 ret
3128
3129 ;
3130 ; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir
3131 ;
3132 loadkeys:
3133 000011D2 21D2 and dx,dx ; Should be 256 bytes exactly
3134 000011D4 751A jne loadkeys_ret
3135 000011D6 3D0001 cmp ax,256
3136 000011D9 7515 jne loadkeys_ret
3137
3138 000011DB BB0010 mov bx,trackbuf
3139 000011DE B90100 mov cx,1 ; 1 cluster should be >= 256 bytes
3140 000011E1 E842F1 call getfssec
3141
3142 000011E4 BE0010 mov si,trackbuf
3143 000011E7 BF0053 mov di,KbdMap
3144 000011EA B94000 mov cx,256 >> 2
3145 000011ED F366A5 rep movsd
3146
3147 000011F0 C3 loadkeys_ret: ret
3148
3149 ;
3150 ; get_msg_file: Load a text file and write its contents to the screen,
3151 ; interpreting color codes. Is called with SI and DX:AX
3152 ; set by routine searchdir
3153 ;
3154 get_msg_file:
3155 000011F1 06 push es
3156 000011F2 66C1E210 shl edx,16 ; EDX <- DX:AX (length of file)
3157 000011F6 89C2 mov dx,ax
3158 000011F8 B80030 mov ax,xfer_buf_seg ; Use for temporary storage
3159 000011FB 8EC0 mov es,ax
3160
3161 000011FD C6063C5507 mov byte [TextAttribute],07h ; Default grey on white
3162 00001202 C6064A5507 mov byte [DisplayMask],07h ; Display text in all modes
3163 00001207 E86001 call msg_initvars
3164
3165 0000120A 6652 get_msg_chunk: push edx ; EDX = length of file
3166 0000120C 31DB xor bx,bx ; == xbs_textbuf
3167 0000120E 8B0E1055 mov cx,[BufSafe]
3168 00001212 E811F1 call getfssec
3169 00001215 665A pop edx
3170 00001217 56 push si ; Save current cluster
3171 00001218 31F6 xor si,si ; == xbs_textbuf
3172 0000121A 8B0E1455 mov cx,[BufSafeBytes] ; Number of bytes left in chunk
3173 print_msg_file:
3174 0000121E 51 push cx
3175 0000121F 6652 push edx
3176 00001221 26AC es lodsb
3177 00001223 3C1A cmp al,1Ah ; DOS EOF?
3178 00001225 7418 je msg_done_pop
3179 00001227 56 push si
3180 00001228 8A0E[CC18] mov cl,[UsingVGA]
3181 0000122C FEC1 inc cl ; 01h = text mode, 02h = graphics
3182 0000122E FF162A55 call [NextCharJump] ; Do what shall be done
3183 00001232 5E pop si
3184 00001233 665A pop edx
3185 00001235 59 pop cx
3186 00001236 664A dec edx
3187 00001238 7408 jz msg_done
3188 0000123A E2E2 loop print_msg_file
3189 0000123C 5E pop si
3190 0000123D EBCB jmp short get_msg_chunk
3191 msg_done_pop:
3192 0000123F 83C406 add sp,byte 6 ; Drop pushed EDX, CX
3193 msg_done:
3194 00001242 5E pop si
3195 00001243 07 pop es
3196 00001244 C3 ret
3197 msg_putchar: ; Normal character
3198 00001245 3C0F cmp al,0Fh ; ^O = color code follows
3199 00001247 744E je msg_ctrl_o
3200 00001249 3C0D cmp al,0Dh ; Ignore <CR>
3201 0000124B 7449 je msg_ignore
3202 0000124D 3C0A cmp al,0Ah ; <LF> = newline
3203 0000124F 744D je msg_newline
3204 00001251 3C0C cmp al,0Ch ; <FF> = clear screen
3205 00001253 747E je msg_formfeed
3206 00001255 3C19 cmp al,19h ; <EM> = return to text mode
3207 00001257 0F84F300 je near msg_novga
3208 0000125B 3C18 cmp al,18h ; <CAN> = VGA filename follows
3209 0000125D 0F84BC00 je near msg_vga
3210 00001261 7306 jnb .not_modectl
3211 00001263 3C10 cmp al,10h ; 10h to 17h are mode controls
3212 00001265 0F831101 jae near msg_modectl
3213 .not_modectl:
3214
3215 00001269 E81501 msg_normal: call write_serial_displaymask ; Write to serial port
3216 0000126C 840E4A55 test [DisplayMask],cl
3217 00001270 7424 jz msg_ignore ; Not screen
3218 00001272 8B1E3C55 mov bx,[TextAttrBX]
3219 00001276 B409 mov ah,09h ; Write character/attribute
3220 00001278 B90100 mov cx,1 ; One character only
3221 0000127B CD10 int 10h ; Write to screen
3222 0000127D A03E55 mov al,[CursorCol]
3223 00001280 40 inc ax
3224 00001281 3A064055 cmp al,[VidCols]
3225 00001285 771D ja msg_line_wrap ; Screen wraparound
3226 00001287 A23E55 mov [CursorCol],al
3227
3228 0000128A 8A3E3D55 msg_gotoxy: mov bh,[TextPage]
3229 0000128E 8B163E55 mov dx,[CursorDX]
3230 00001292 B402 mov ah,02h ; Set cursor position
3231 00001294 CD10 int 10h
3232 00001296 C3 msg_ignore: ret
3233 msg_ctrl_o: ; ^O = color code follows
3234 00001297 C7062A55[F412] mov word [NextCharJump],msg_setbg
3235 0000129D C3 ret
3236 msg_newline: ; Newline char or end of line
3237 0000129E BE[F81C] mov si,crlf_msg
3238 000012A1 E81001 call write_serial_str_displaymask
3239 msg_line_wrap: ; Screen wraparound
3240 000012A4 840E4A55 test [DisplayMask],cl
3241 000012A8 74EC jz msg_ignore
3242 000012AA C6063E5500 mov byte [CursorCol],0
3243 000012AF A03F55 mov al,[CursorRow]
3244 000012B2 40 inc ax
3245 000012B3 3A064155 cmp al,[VidRows]
3246 000012B7 7705 ja msg_scroll
3247 000012B9 A23F55 mov [CursorRow],al
3248 000012BC EBCC jmp short msg_gotoxy
3249 000012BE 31C9 msg_scroll: xor cx,cx ; Upper left hand corner
3250 000012C0 8B164055 mov dx,[ScreenSize]
3251 000012C4 88363F55 mov [CursorRow],dh ; New cursor at the bottom
3252 000012C8 8A3E[7B1D] mov bh,[ScrollAttribute]
3253 000012CC B80106 mov ax,0601h ; Scroll up one line
3254 000012CF CD10 int 10h
3255 000012D1 EBB7 jmp short msg_gotoxy
3256 msg_formfeed: ; Form feed character
3257 000012D3 BE[FB1C] mov si,crff_msg
3258 000012D6 E8DB00 call write_serial_str_displaymask
3259 000012D9 840E4A55 test [DisplayMask],cl
3260 000012DD 74B7 jz msg_ignore
3261 000012DF 31C9 xor cx,cx
3262 000012E1 890E3E55 mov [CursorDX],cx ; Upper lefthand corner
3263 000012E5 8B164055 mov dx,[ScreenSize]
3264 000012E9 8A3E3C55 mov bh,[TextAttribute]
3265 000012ED B80006 mov ax,0600h ; Clear screen region
3266 000012F0 CD10 int 10h
3267 000012F2 EB96 jmp short msg_gotoxy
3268 msg_setbg: ; Color background character
3269 000012F4 E8FA02 call unhexchar
3270 000012F7 722F jc msg_color_bad
3271 000012F9 C0E004 shl al,4
3272 000012FC 840E4A55 test [DisplayMask],cl
3273 00001300 7403 jz .dontset
3274 00001302 A23C55 mov [TextAttribute],al
3275 .dontset:
3276 00001305 C7062A55[0C13] mov word [NextCharJump],msg_setfg
3277 0000130B C3 ret
3278 msg_setfg: ; Color foreground character
3279 0000130C E8E202 call unhexchar
3280 0000130F 7217 jc msg_color_bad
3281 00001311 840E4A55 test [DisplayMask],cl
3282 00001315 7404 jz .dontset
3283 00001317 08063C55 or [TextAttribute],al ; setbg set foreground to 0
3284 .dontset:
3285 0000131B EB10 jmp short msg_putcharnext
3286 msg_vga:
3287 0000131D C7062A55[3413] mov word [NextCharJump],msg_filename
3288 00001323 BF8C55 mov di, VGAFileBuf
3289 00001326 EB21 jmp short msg_setvgafileptr
3290
3291 msg_color_bad:
3292 00001328 C6063C5507 mov byte [TextAttribute],07h ; Default attribute
3293 msg_putcharnext:
3294 0000132D C7062A55[4512] mov word [NextCharJump],msg_putchar
3295 00001333 C3 ret
3296
3297 msg_filename: ; Getting VGA filename
3298 00001334 3C0A cmp al,0Ah ; <LF> = end of filename
3299 00001336 741B je msg_viewimage
3300 00001338 3C20 cmp al,' '
3301 0000133A 7611 jbe msg_ret ; Ignore space/control char
3302 0000133C 8B3E3A55 mov di,[VGAFilePtr]
3303 00001340 81FF9955 cmp di,VGAFileBufEnd
3304 00001344 7307 jnb msg_ret
3305 00001346 8805 mov [di],al ; Can't use stosb (DS:)
3306 00001348 47 inc di
3307 msg_setvgafileptr:
3308 00001349 893E3A55 mov [VGAFilePtr],di
3309 0000134D C3 msg_ret: ret
3310
3311 msg_novga:
3312 0000134E E82405 call vgaclearmode
3313 00001351 EB17 jmp short msg_initvars
3314
3315 msg_viewimage:
3316 00001353 06 push es
3317 00001354 1E push ds
3318 00001355 07 pop es ; ES <- DS
3319 00001356 BE8C55 mov si,VGAFileBuf
3320 00001359 BF9955 mov di,VGAFileMBuf
3321 0000135C 57 push di
3322 0000135D E8E802 call mangle_name
3323 00001360 5F pop di
3324 00001361 E84CFD call searchdir
3325 00001364 07 pop es
3326 00001365 74C6 jz msg_putcharnext ; Not there
3327 00001367 E88503 call vgadisplayfile
3328 ; Fall through
3329
3330 ; Subroutine to initialize variables, also needed
3331 ; after loading a graphics file
3332 msg_initvars:
3333 0000136A 60 pusha
3334 0000136B 8A3E3D55 mov bh,[TextPage]
3335 0000136F B403 mov ah,03h ; Read cursor position
3336 00001371 CD10 int 10h
3337 00001373 89163E55 mov [CursorDX],dx
3338 00001377 61 popa
3339 00001378 EBB3 jmp short msg_putcharnext ; Initialize state machine
3340
3341 msg_modectl:
3342 0000137A 2407 and al,07h
3343 0000137C A24A55 mov [DisplayMask],al
3344 0000137F EBAC jmp short msg_putcharnext
3345
3346 ;
3347 ; write_serial: If serial output is enabled, write character on serial port
3348 ; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0
3349 ;
3350 write_serial_displaymask:
3351 00001381 F6064A5504 test byte [DisplayMask], 04h
3352 00001386 742B jz write_serial.end
3353 write_serial:
3354 00001388 669C pushfd
3355 0000138A 6660 pushad
3356 0000138C 8B1E[601D] mov bx,[SerialPort]
3357 00001390 21DB and bx,bx
3358 00001392 741B je .noserial
3359 00001394 50 push ax
3360 00001395 8A264355 mov ah,[FlowInput]
3361 .waitspace:
3362 ; Wait for space in transmit register
3363 00001399 8D5705 lea dx,[bx+5] ; DX -> LSR
3364 0000139C EC in al,dx
3365 0000139D A820 test al,20h
3366 0000139F 74F8 jz .waitspace
3367
3368 ; Wait for input flow control
3369 000013A1 42 inc dx ; DX -> MSR
3370 000013A2 EC in al,dx
3371 000013A3 20E0 and al,ah
3372 000013A5 38E0 cmp al,ah
3373 000013A7 75F0 jne .waitspace
3374 .no_flow:
3375
3376 000013A9 87D3 xchg dx,bx ; DX -> THR
3377 000013AB 58 pop ax
3378 000013AC E84EFB call slow_out ; Send data
3379 000013AF 6661 .noserial: popad
3380 000013B1 669D popfd
3381 000013B3 C3 .end: ret
3382
3383 ;
3384 ; write_serial_str: write_serial for strings
3385 ; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
3386 ;
3387 write_serial_str_displaymask:
3388 000013B4 F6064A5504 test byte [DisplayMask], 04h
3389 000013B9 740A jz write_serial_str.end
3390
3391 write_serial_str:
3392 000013BB AC .loop lodsb
3393 000013BC 20C0 and al,al
3394 000013BE 7405 jz .end
3395 000013C0 E8C5FF call write_serial
3396 000013C3 EBF6 jmp short .loop
3397 000013C5 C3 .end: ret
3398
3399 ;
3400 ; writechr: Write a single character in AL to the console without
3401 ; mangling any registers
3402 ;
3403 writechr:
3404 000013C6 E8BFFF call write_serial ; write to serial port if needed
3405 000013C9 669C pushfd
3406 000013CB 6660 pushad
3407 000013CD B40E mov ah,0Eh
3408 000013CF BB0700 mov bx,0007h ; white text on this page
3409 000013D2 CD10 int 10h
3410 000013D4 6661 popad
3411 000013D6 669D popfd
3412 000013D8 C3 ret
3413
3414 ;
3415 ; crlf: Print a newline
3416 ;
3417 000013D9 BE[F81C] crlf: mov si,crlf_msg
3418 ; Fall through
3419
3420 ;
3421 ; cwritestr: write a null-terminated string to the console, saving
3422 ; registers on entry.
3423 ;
3424 cwritestr:
3425 000013DC 669C pushfd
3426 000013DE 6660 pushad
3427 000013E0 AC .top: lodsb
3428 000013E1 20C0 and al,al
3429 000013E3 7405 jz .end
3430 000013E5 E8DEFF call writechr
3431 000013E8 EBF6 jmp short .top
3432 000013EA 6661 .end: popad
3433 000013EC 669D popfd
3434 000013EE C3 ret
3435
3436 %ifdef debug
3437
3438 ;
3439 ; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
3440 ;
3441 writehex2:
3442 pushfd
3443 pushad
3444 rol eax,24
3445 mov cx,2
3446 jmp short writehex_common
3447 writehex4:
3448 pushfd
3449 pushad
3450 rol eax,16
3451 mov cx,4
3452 jmp short writehex_common
3453 writehex8:
3454 pushfd
3455 pushad
3456 mov cx,8
3457 writehex_common:
3458 .loop: rol eax,4
3459 push eax
3460 and al,0Fh
3461 cmp al,10
3462 jae .high
3463 .low: add al,'0'
3464 jmp short .ischar
3465 .high: add al,'A'-10
3466 .ischar: call writechr
3467 pop eax
3468 loop .loop
3469 popad
3470 popfd
3471 ret
3472
3473 ;
3474 ; crlf: write CR LF
3475 ;
3476 crlf: push ax
3477 mov al, 13
3478 call writechr
3479 mov al, 10
3480 call writechr
3481 pop ax
3482 ret
3483
3484 %endif
3485
3486 ;
3487 ; pollchar: check if we have an input character pending (ZF = 0)
3488 ;
3489 pollchar:
3490 000013EF 6660 pushad
3491 000013F1 B401 mov ah,1 ; Poll keyboard
3492 000013F3 CD16 int 16h
3493 000013F5 751F jnz .done ; Keyboard response
3494 000013F7 8B16[601D] mov dx,[SerialPort]
3495 000013FB 21D2 and dx,dx
3496 000013FD 7417 jz .done ; No serial port -> no input
3497 000013FF 83C205 add dx,byte 5 ; DX -> LSR
3498 00001402 EC in al,dx
3499 00001403 A801 test al,1 ; ZF = 0 if data pending
3500 00001405 740F jz .done
3501 00001407 42 inc dx ; DX -> MSR
3502 00001408 8A264455 mov ah,[FlowIgnore] ; Required status bits
3503 0000140C EC in al,dx
3504 0000140D 20E0 and al,ah
3505 0000140F 38E0 cmp al,ah
3506 00001411 0F95C0 setne al
3507 00001414 FEC8 dec al ; Set ZF = 0 if equal
3508 00001416 6661 .done: popad
3509 00001418 C3 ret
3510
3511 ;
3512 ; getchar: Read a character from keyboard or serial port
3513 ;
3514 getchar:
3515 00001419 B401 .again: mov ah,1 ; Poll keyboard
3516 0000141B CD16 int 16h
3517 0000141D 7522 jnz .kbd ; Keyboard input?
3518 0000141F 8B1E[601D] mov bx,[SerialPort]
3519 00001423 21DB and bx,bx
3520 00001425 74F2 jz .again
3521 00001427 8D5705 lea dx,[bx+5] ; DX -> LSR
3522 0000142A EC in al,dx
3523 0000142B A801 test al,1
3524 0000142D 74EA jz .again
3525 0000142F 42 inc dx ; DX -> MSR
3526 00001430 8A264455 mov ah,[FlowIgnore]
3527 00001434 EC in al,dx
3528 00001435 20E0 and al,ah
3529 00001437 38E0 cmp al,ah
3530 00001439 75DE jne .again
3531 0000143B 30E4 .serial: xor ah,ah ; Avoid confusion
3532 0000143D 87D3 xchg dx,bx ; Data port
3533 0000143F EC in al,dx
3534 00001440 C3 ret
3535 00001441 31C0 .kbd: xor ax,ax ; Get keyboard input
3536 00001443 CD16 int 16h
3537 00001445 20C0 and al,al
3538 00001447 7404 jz .func_key
3539 00001449 BB0053 mov bx,KbdMap ; Convert character sets
3540 0000144C D7 xlatb
3541 0000144D C3 .func_key: ret
3542
3543 ;
3544 ;
3545 ; kaboom2: once everything is loaded, replace the part of kaboom
3546 ; starting with "kaboom.patch" with this part
3547
3548 kaboom2:
3549 0000144E BE[971C] mov si,err_bootfailed
3550 00001451 E888FF call cwritestr
3551 00001454 E8C2FF call getchar
3552 00001457 E81B04 call vgaclearmode
3553 0000145A CD19 int 19h ; And try once more to boot...
3554 0000145C EBFE .norge: jmp short .norge ; If int 19h returned; this is the end
3555
3556 ;
3557 ; open,getc: Load a file a character at a time for parsing in a manner
3558 ; similar to the C library getc routine. Only one simultaneous
3559 ; use is supported. Note: "open" trashes the trackbuf.
3560 ;
3561 ; open: Input: mangled filename in DS:DI
3562 ; Output: ZF set on file not found or zero length
3563 ;
3564 ; getc: Output: CF set on end of file
3565 ; Character loaded in AL
3566 ;
3567 open:
3568 0000145E E84FFC call searchdir
3569 00001461 7427 jz open_return
3570 00001463 9C pushf
3571 00001464 A3FC54 mov [FBytes1],ax
3572 00001467 8916FE54 mov [FBytes2],dx
3573 0000146B 03060A55 add ax,[ClustSize]
3574 0000146F 83D200 adc dx,byte 0
3575 00001472 83E801 sub ax,byte 1
3576 00001475 83DA00 sbb dx,byte 0
3577 00001478 F7360A55 div word [ClustSize]
3578 0000147C A31E55 mov [FClust],ax ; Number of clusters
3579 0000147F 89362055 mov [FNextClust],si ; Cluster pointer
3580 00001483 A11655 mov ax,[EndOfGetCBuf] ; Pointer at end of buffer ->
3581 00001486 A32255 mov [FPtr],ax ; nothing loaded yet
3582 00001489 9D popf ; Restore no ZF
3583 0000148A C3 open_return: ret
3584
3585 ;
3586 getc:
3587 0000148B F9 stc ; If we exit here -> EOF
3588 0000148C 668B0EFC54 mov ecx,[FBytes]
3589 00001491 66E33B jecxz getc_ret
3590 00001494 8B362255 mov si,[FPtr]
3591 00001498 3B361655 cmp si,[EndOfGetCBuf]
3592 0000149C 7226 jb getc_loaded
3593 ; Buffer empty -- load another set
3594 0000149E 8B0E1E55 mov cx,[FClust]
3595 000014A2 3B0E1055 cmp cx,[BufSafe]
3596 000014A6 7604 jna getc_oksize
3597 000014A8 8B0E1055 mov cx,[BufSafe]
3598 000014AC 290E1E55 getc_oksize: sub [FClust],cx ; Reduce remaining clusters
3599 000014B0 8B362055 mov si,[FNextClust]
3600 000014B4 BB009C mov bx,getcbuf
3601 000014B7 53 push bx
3602 000014B8 06 push es ; ES may be != DS, save old ES
3603 000014B9 1E push ds ; Trackbuf is in DS, not ES
3604 000014BA 07 pop es
3605 000014BB E868EE call getfssec ; Load a trackbuf full of data
3606 000014BE 89362055 mov [FNextClust],si ; Store new next pointer
3607 000014C2 07 pop es ; Restore ES
3608 000014C3 5E pop si ; SI -> newly loaded data
3609 000014C4 AC getc_loaded: lodsb ; Load a byte
3610 000014C5 89362255 mov [FPtr],si ; Update next byte pointer
3611 000014C9 66FF0EFC54 dec dword [FBytes] ; Update bytes left counter (CF = 1)
3612 000014CE F8 clc ; Not EOF
3613 000014CF C3 getc_ret: ret
3614
3615 ;
3616 ; ungetc: Push a character (in AL) back into the getc buffer
3617 ; Note: if more than one byte is pushed back, this may cause
3618 ; bytes to be written below the getc buffer boundary. If there
3619 ; is a risk for this to occur, the getcbuf base address should
3620 ; be moved up.
3621 ;
3622 ungetc:
3623 000014D0 8B362255 mov si,[FPtr]
3624 000014D4 4E dec si
3625 000014D5 8804 mov [si],al
3626 000014D7 89362255 mov [FPtr],si
3627 000014DB 66FF06FC54 inc dword [FBytes]
3628 000014E0 C3 ret
3629
3630 ;
3631 ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line
3632 ; or end-of-file, return with carry set; ZF = true of EOF
3633 ; ZF = false for EOLN; otherwise CF = ZF = 0.
3634 ;
3635 ; Otherwise AL = first character after whitespace
3636 ;
3637 skipspace:
3638 000014E1 E8A7FF skipspace_loop: call getc
3639 000014E4 720D jc skipspace_eof
3640 000014E6 3C1A cmp al,1Ah ; DOS EOF
3641 000014E8 7409 je skipspace_eof
3642 000014EA 3C0A cmp al,0Ah
3643 000014EC 7409 je skipspace_eoln
3644 000014EE 3C20 cmp al,' '
3645 000014F0 76EF jbe skipspace_loop
3646 000014F2 C3 ret ; CF = ZF = 0
3647 000014F3 38C0 skipspace_eof: cmp al,al ; Set ZF
3648 000014F5 F9 stc ; Set CF
3649 000014F6 C3 ret
3650 000014F7 04FF skipspace_eoln: add al,0FFh ; Set CF, clear ZF
3651 000014F9 C3 ret
3652
3653 ;
3654 ; getkeyword: Get a keyword from the current "getc" file; only the two
3655 ; first characters are considered significant.
3656 ;
3657 ; Lines beginning with ASCII characters 33-47 are treated
3658 ; as comments and ignored; other lines are checked for
3659 ; validity by scanning through the keywd_table.
3660 ;
3661 ; The keyword and subsequent whitespace is skipped.
3662 ;
3663 ; On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair
3664 ;
3665 getkeyword:
3666 000014FA E8E4FF gkw_find: call skipspace
3667 000014FD 7438 jz gkw_eof ; end of file
3668 000014FF 72F9 jc gkw_find ; end of line: try again
3669 00001501 3C30 cmp al,'0'
3670 00001503 7246 jb gkw_skipline ; skip comment line
3671 00001505 50 push ax
3672 00001506 E882FF call getc
3673 00001509 5B pop bx
3674 0000150A 722B jc gkw_eof
3675 0000150C 88C7 mov bh,al ; Move character pair into BL:BH
3676 0000150E 81CB2020 or bx,2020h ; Lower-case it
3677 00001512 BE[101D] mov si,keywd_table
3678 00001515 AD gkw_check: lodsw
3679 00001516 21C0 and ax,ax
3680 00001518 7429 jz gkw_badline ; Bad keyword, write message
3681 0000151A 39D8 cmp ax,bx
3682 0000151C 75F7 jne gkw_check
3683 0000151E 50 push ax
3684 gkw_skiprest:
3685 0000151F E869FF call getc
3686 00001522 7212 jc gkw_eof_pop
3687 00001524 3C30 cmp al,'0'
3688 00001526 77F7 ja gkw_skiprest
3689 00001528 E8A5FF call ungetc
3690 0000152B E8B3FF call skipspace
3691 0000152E 7406 jz gkw_eof_pop
3692 00001530 7206 jc gkw_missingpar ; Missing parameter after keyword
3693 00001532 E89BFF call ungetc ; Return character to buffer
3694 00001535 F8 clc ; Successful return
3695 00001536 58 gkw_eof_pop: pop ax
3696 00001537 C3 gkw_eof: ret ; CF = 1 on all EOF conditions
3697 00001538 58 gkw_missingpar: pop ax
3698 00001539 BE[561B] mov si,err_noparm
3699 0000153C E89DFE call cwritestr
3700 0000153F E9B8FF jmp gkw_find
3701 00001542 58 gkw_badline_pop: pop ax
3702 00001543 BE[331B] gkw_badline: mov si,err_badcfg
3703 00001546 E893FE call cwritestr
3704 00001549 EBAF jmp short gkw_find
3705 0000154B 3C0A gkw_skipline: cmp al,10 ; Scan for LF
3706 0000154D 74AB je gkw_find
3707 0000154F E839FF call getc
3708 00001552 72E3 jc gkw_eof
3709 00001554 EBF5 jmp short gkw_skipline
3710
3711 ;
3712 ; getint: Load an integer from the getc file.
3713 ; Return CF if error; otherwise return integer in EBX
3714 ;
3715 getint:
3716 00001556 BFA054 mov di,NumBuf
3717 00001559 81FFAF54 gi_getnum: cmp di,NumBufEnd ; Last byte in NumBuf
3718 0000155D 730F jae gi_loaded
3719 0000155F 57 push di
3720 00001560 E828FF call getc
3721 00001563 5F pop di
3722 00001564 7208 jc gi_loaded
3723 00001566 AA stosb
3724 00001567 3C2D cmp al,'-'
3725 00001569 73EE jnb gi_getnum
3726 0000156B E862FF call ungetc ; Unget non-numeric
3727 0000156E C60500 gi_loaded: mov byte [di],0
3728 00001571 BEA054 mov si,NumBuf
3729 ; Fall through to parseint
3730
3731 ;
3732 ; parseint: Convert an integer to a number in EBX
3733 ; Get characters from string in DS:SI
3734 ; Return CF on error
3735 ; DS:SI points to first character after number
3736 ;
3737 ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M
3738 ;
3739 parseint:
3740 00001574 6650 push eax
3741 00001576 6651 push ecx
3742 00001578 55 push bp
3743 00001579 6631C0 xor eax,eax ; Current digit (keep eax == al)
3744 0000157C 6689C3 mov ebx,eax ; Accumulator
3745 0000157F 6689D9 mov ecx,ebx ; Base
3746 00001582 31ED xor bp,bp ; Used for negative flag
3747 00001584 AC pi_begin: lodsb
3748 00001585 3C2D cmp al,'-'
3749 00001587 7506 jne pi_not_minus
3750 00001589 81F50100 xor bp,1 ; Set unary minus flag
3751 0000158D EBF5 jmp short pi_begin
3752 pi_not_minus:
3753 0000158F 3C30 cmp al,'0'
3754 00001591 724F jb pi_err
3755 00001593 7408 je pi_octhex
3756 00001595 3C39 cmp al,'9'
3757 00001597 7749 ja pi_err
3758 00001599 B10A mov cl,10 ; Base = decimal
3759 0000159B EB17 jmp short pi_foundbase
3760 pi_octhex:
3761 0000159D AC lodsb
3762 0000159E 3C30 cmp al,'0'
3763 000015A0 7225 jb pi_km ; Value is zero
3764 000015A2 0C20 or al,20h ; Downcase
3765 000015A4 3C78 cmp al,'x'
3766 000015A6 7408 je pi_ishex
3767 000015A8 3C37 cmp al,'7'
3768 000015AA 7736 ja pi_err
3769 000015AC B108 mov cl,8 ; Base = octal
3770 000015AE EB04 jmp short pi_foundbase
3771 pi_ishex:
3772 000015B0 B030 mov al,'0' ; No numeric value accrued yet
3773 000015B2 B110 mov cl,16 ; Base = hex
3774 pi_foundbase:
3775 000015B4 E83A00 call unhexchar
3776 000015B7 720E jc pi_km ; Not a (hex) digit
3777 000015B9 38C8 cmp al,cl
3778 000015BB 730A jae pi_km ; Invalid for base
3779 000015BD 660FAFD9 imul ebx,ecx ; Multiply accumulated by base
3780 000015C1 6601C3 add ebx,eax ; Add current digit
3781 000015C4 AC lodsb
3782 000015C5 EBED jmp short pi_foundbase
3783 pi_km:
3784 000015C7 4E dec si ; Back up to last non-numeric
3785 000015C8 AC lodsb
3786 000015C9 0C20 or al,20h
3787 000015CB 3C6B cmp al,'k'
3788 000015CD 7416 je pi_isk
3789 000015CF 3C6D cmp al,'m'
3790 000015D1 7418 je pi_ism
3791 000015D3 4E dec si ; Back up
3792 000015D4 21ED pi_fini: and bp,bp
3793 000015D6 7404 jz pi_ret ; CF=0!
3794 000015D8 66F7DB neg ebx ; Value was negative
3795 000015DB F8 pi_done: clc
3796 000015DC 5D pi_ret: pop bp
3797 000015DD 6659 pop ecx
3798 000015DF 6658 pop eax
3799 000015E1 C3 ret
3800 000015E2 F9 pi_err: stc
3801 000015E3 EBF7 jmp short pi_ret
3802 000015E5 66C1E30A pi_isk: shl ebx,10 ; x 2^10
3803 000015E9 EBF0 jmp short pi_done
3804 000015EB 66C1E314 pi_ism: shl ebx,20 ; x 2^20
3805 000015EF EBEA jmp short pi_done
3806
3807 ;
3808 ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
3809 ; return CF=1 if not a hex digit
3810 ;
3811 unhexchar:
3812 000015F1 3C30 cmp al,'0'
3813 000015F3 7215 jb uxc_ret ; If failure, CF == 1 already
3814 000015F5 3C39 cmp al,'9'
3815 000015F7 7703 ja uxc_1
3816 000015F9 2C30 sub al,'0' ; CF <- 0
3817 000015FB C3 ret
3818 000015FC 0C20 uxc_1: or al,20h ; upper case -> lower case
3819 000015FE 3C61 cmp al,'a'
3820 00001600 7208 jb uxc_ret ; If failure, CF == 1 already
3821 00001602 3C66 cmp al,'f'
3822 00001604 7703 ja uxc_err
3823 00001606 2C57 sub al,'a'-10 ; CF <- 0
3824 00001608 C3 ret
3825 00001609 F9 uxc_err: stc
3826 0000160A C3 uxc_ret: ret
3827
3828 ;
3829 ;
3830 ; getline: Get a command line, converting control characters to spaces
3831 ; and collapsing streches to one; a space is appended to the
3832 ; end of the string, unless the line is empty.
3833 ; The line is terminated by ^J, ^Z or EOF and is written
3834 ; to ES:DI. On return, DI points to first char after string.
3835 ; CF is set if we hit EOF.
3836 ;
3837 getline:
3838 0000160B E8D3FE call skipspace
3839 0000160E B201 mov dl,1 ; Empty line -> empty string.
3840 00001610 742B jz gl_eof ; eof
3841 00001612 7226 jc gl_eoln ; eoln
3842 00001614 E8B9FE call ungetc
3843 00001617 52 gl_fillloop: push dx
3844 00001618 57 push di
3845 00001619 E86FFE call getc
3846 0000161C 5F pop di
3847 0000161D 5A pop dx
3848 0000161E 721E jc gl_ret ; CF set!
3849 00001620 3C20 cmp al,' '
3850 00001622 7605 jna gl_ctrl
3851 00001624 31D2 xor dx,dx
3852 00001626 AA gl_store: stosb
3853 00001627 EBEE jmp short gl_fillloop
3854 00001629 3C0A gl_ctrl: cmp al,10
3855 0000162B 7411 je gl_ret ; CF clear!
3856 0000162D 3C1A cmp al,26
3857 0000162F 740C je gl_eof
3858 00001631 20D2 and dl,dl
3859 00001633 75E2 jnz gl_fillloop ; Ignore multiple spaces
3860 00001635 B020 mov al,' ' ; Ctrl -> space
3861 00001637 42 inc dx
3862 00001638 EBEC jmp short gl_store
3863 0000163A F8 gl_eoln: clc ; End of line is not end of file
3864 0000163B EB01 jmp short gl_ret
3865 0000163D F9 gl_eof: stc
3866 0000163E 9C gl_ret: pushf ; We want the last char to be space!
3867 0000163F 20D2 and dl,dl
3868 00001641 7503 jnz gl_xret
3869 00001643 B020 mov al,' '
3870 00001645 AA stosb
3871 00001646 9D gl_xret: popf
3872 00001647 C3 ret
3873
3874
3875 ;
3876 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
3877 ; to by ES:DI; ends on encountering any whitespace
3878 ;
3879
3880 mangle_name:
3881 00001648 B90B00 mov cx,11 ; # of bytes to write
3882 mn_loop:
3883 0000164B AC lodsb
3884 0000164C 3C20 cmp al,' ' ; If control or space, end
3885 0000164E 762B jna mn_end
3886 00001650 3C2E cmp al,'.' ; Period -> space-fill
3887 00001652 740C je mn_is_period
3888 00001654 3C61 cmp al,'a'
3889 00001656 7220 jb mn_not_lower
3890 00001658 3C7A cmp al,'z'
3891 0000165A 770F ja mn_not_uslower
3892 0000165C 2C20 sub al,020h
3893 0000165E EB18 jmp short mn_not_lower
3894 00001660 B020 mn_is_period: mov al,' ' ; We need to space-fill
3895 00001662 81F90300 mn_period_loop: cmp cx,3 ; If <= 3 characters left
3896 00001666 76E3 jbe mn_loop ; Just ignore it
3897 00001668 AA stosb ; Otherwise, write a period
3898 00001669 E2F7 loop mn_period_loop ; Dec CX and (always) jump
3899 0000166B 3C81 mn_not_uslower: cmp al,ucase_low
3900 0000166D 7209 jb mn_not_lower
3901 0000166F 3CA4 cmp al,ucase_high
3902 00001671 7705 ja mn_not_lower
3903 00001673 BB[FF15] mov bx,ucase_tab-ucase_low
3904 00001676 2ED7 cs xlatb
3905 00001678 AA mn_not_lower: stosb
3906 00001679 E2D0 loop mn_loop ; Don't continue if too long
3907 mn_end:
3908 0000167B B020 mov al,' ' ; Space-fill name
3909 0000167D F3AA rep stosb ; Doesn't do anything if CX=0
3910 0000167F C3 ret ; Done
3911
3912 ;
3913 ; Upper-case table for extended characters; this is technically code page 865,
3914 ; but code page 437 users will probably not miss not being able to use the
3915 ; cent sign in kernel images too much :-)
3916 ;
3917 ; The table only covers the range 129 to 164; the rest we can deal with.
3918 ;
3919 ucase_low equ 129
3920 ucase_high equ 164
3921 00001680 9A90418E418F804545- ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
3922 00001689 45494949
3923 0000168D 8E8F9092924F994F55- db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
3924 00001696 5559999A
3925 0000169A 9D9C9D9E9F41494F55- db 157, 156, 157, 158, 159, 'AIOU', 165
3926 000016A3 A5
3927
3928 ;
3929 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
3930 ; filename to the conventional representation. This is needed
3931 ; for the BOOT_IMAGE= parameter for the kernel.
3932 ; NOTE: A 13-byte buffer is mandatory, even if the string is
3933 ; known to be shorter.
3934 ;
3935 ; DS:SI -> input mangled file name
3936 ; ES:DI -> output buffer
3937 ;
3938 ; On return, DI points to the first byte after the output name,
3939 ; which is set to a null byte.
3940 ;
3941 unmangle_name:
3942 000016A4 56 push si ; Save pointer to original name
3943 000016A5 B90800 mov cx,8
3944 000016A8 89FD mov bp,di
3945 000016AA AC un_copy_body: lodsb
3946 000016AB E82600 call lower_case
3947 000016AE AA stosb
3948 000016AF 3C20 cmp al,' '
3949 000016B1 7602 jbe un_cb_space
3950 000016B3 89FD mov bp,di ; Position of last nonblank+1
3951 000016B5 E2F3 un_cb_space: loop un_copy_body
3952 000016B7 89EF mov di,bp
3953 000016B9 B02E mov al,'.' ; Don't save
3954 000016BB AA stosb
3955 000016BC B90300 mov cx,3
3956 000016BF AC un_copy_ext: lodsb
3957 000016C0 E81100 call lower_case
3958 000016C3 AA stosb
3959 000016C4 3C20 cmp al,' '
3960 000016C6 7602 jbe un_ce_space
3961 000016C8 89FD mov bp,di
3962 000016CA E2F3 un_ce_space: loop un_copy_ext
3963 000016CC 89EF mov di,bp
3964 000016CE 26C60500 mov byte [es:di], 0
3965 000016D2 5E pop si
3966 000016D3 C3 ret
3967
3968 ;
3969 ; lower_case: Lower case a character in AL
3970 ;
3971 lower_case:
3972 000016D4 3C41 cmp al,'A'
3973 000016D6 7216 jb lc_ret
3974 000016D8 3C5A cmp al,'Z'
3975 000016DA 7703 ja lc_1
3976 000016DC 0C20 or al,20h
3977 000016DE C3 ret
3978 000016DF 3C80 lc_1: cmp al,lcase_low
3979 000016E1 720B jb lc_ret
3980 000016E3 3CA5 cmp al,lcase_high
3981 000016E5 7707 ja lc_ret
3982 000016E7 53 push bx
3983 000016E8 BB[4D18] mov bx,lcase_tab-lcase_low
3984 000016EB 2ED7 cs xlatb
3985 000016ED 5B pop bx
3986 000016EE C3 lc_ret: ret
3987
3988 ; ----------------------------------------------------------------------------------
3989 ; VGA splash screen code
3990 ; ----------------------------------------------------------------------------------
3991
3992 ;
3993 ; vgadisplayfile:
3994 ; Display a graphical splash screen.
3995 ;
3996 ; Input:
3997 ;
3998 ; SI = cluster/socket pointer
3999 ;
4000 vgadisplayfile:
4001 000016EF 89363855 mov [VGACluster],si
4002 000016F3 06 push es
4003
4004 ; This is a cheap and easy way to make sure the screen is
4005 ; cleared in case we were in graphics mode already
4006 000016F4 E87E01 call vgaclearmode
4007 000016F7 E85001 call vgasetmode
4008 000016FA 7514 jnz .error_nz
4009
4010 .graphalready:
4011 000016FC B80030 mov ax,xfer_buf_seg ; Use as temporary storage
4012 000016FF 8EC0 mov es,ax
4013 00001701 8EE0 mov fs,ax
4014
4015 00001703 E8F600 call vgagetchunk ; Get the first chunk
4016
4017 ; The header WILL be in the first chunk.
4018 00001706 2666813E00403DF313- cmp dword [es:xbs_vgabuf],0x1413f33d ; Magic number
4019 0000170F 14
4020 00001710 0F857D00 .error_nz: jne near .error
4021 00001714 26A10440 mov ax,[es:xbs_vgabuf+4]
4022 00001718 A33455 mov [GraphXSize],ax
4023
4024 0000171B BA0840 mov dx,xbs_vgabuf+8 ; Color map offset
4025 0000171E B81210 mov ax,1012h ; Set RGB registers
4026 00001721 31DB xor bx,bx ; First register number
4027 00001723 B91000 mov cx,16 ; 16 registers
4028 00001726 CD10 int 10h
4029
4030 .movecursor:
4031 00001728 26A10640 mov ax,[es:xbs_vgabuf+6] ; Number of pixel rows
4032 0000172C 8B16[781D] mov dx,[VGAFontSize]
4033 00001730 01D0 add ax,dx
4034 00001732 48 dec ax
4035 00001733 F6F2 div dl
4036 00001735 31D2 xor dx,dx ; Set column to 0
4037 00001737 3A064155 cmp al,[VidRows]
4038 0000173B 7205 jb .rowsok
4039 0000173D A04155 mov al,[VidRows]
4040 00001740 FEC8 dec al
4041 .rowsok:
4042 00001742 88C6 mov dh,al
4043 00001744 B402 mov ah,2
4044 00001746 31DB xor bx,bx
4045 00001748 CD10 int 10h ; Set cursor below image
4046
4047 0000174A 268B0E0640 mov cx,[es:xbs_vgabuf+6] ; Number of graphics rows
4048
4049 0000174F BE3840 mov si,xbs_vgabuf+8+3*16 ; Beginning of pixel data
4050 00001752 C70636550000 mov word [VGAPos],0
4051
4052 .drawpixelrow:
4053 00001758 51 push cx
4054 00001759 8B0E3455 mov cx,[GraphXSize]
4055 0000175D BF0080 mov di,xbs_vgatmpbuf ; Row buffer
4056 00001760 E83000 call rledecode ; Decode one row
4057 00001763 56 push si
4058 00001764 BE0080 mov si,xbs_vgatmpbuf
4059 00001767 89F7 mov di,si
4060 00001769 033E3455 add di,[GraphXSize]
4061 0000176D B9A000 mov cx,640/4
4062 00001770 6631C0 xor eax,eax
4063 00001773 F366AB rep stosd ; Clear rest of row
4064 00001776 BF00A0 mov di,0A000h ; VGA segment
4065 00001779 8EC7 mov es,di
4066 0000177B 8B3E3655 mov di,[VGAPos]
4067 0000177F BD8002 mov bp,640
4068 00001782 E89600 call packedpixel2vga
4069 00001785 8306365550 add word [VGAPos],byte 80 ; Advance to next pixel row
4070 0000178A 0FA0 push fs
4071 0000178C 07 pop es
4072 0000178D 5E pop si
4073 0000178E 59 pop cx
4074 0000178F E2C7 loop .drawpixelrow
4075
4076 .error:
4077 00001791 07 pop es
4078 00001792 C3 ret
4079
4080 ;
4081 ; rledecode:
4082 ; Decode a pixel row in RLE16 format.
4083 ;
4084 ; FS:SI -> input
4085 ; CX -> pixel count
4086 ; ES:DI -> output (packed pixel)
4087 ;
4088 rledecode:
4089 00001793 66D1E6 shl esi,1 ; Nybble pointer
4090 00001796 30D2 xor dl,dl ; Last pixel
4091 .loop:
4092 00001798 E83F00 call .getnybble
4093 0000179B 38D0 cmp al,dl
4094 0000179D 740D je .run ; Start of run sequence
4095 0000179F AA stosb
4096 000017A0 88C2 mov dl,al
4097 000017A2 49 dec cx
4098 000017A3 75F3 jnz .loop
4099 .done:
4100 000017A5 66D1EE shr esi,1
4101 000017A8 83D600 adc si,byte 0
4102 000017AB C3 ret
4103 .run:
4104 000017AC 31DB xor bx,bx
4105 000017AE E82900 call .getnybble
4106 000017B1 20C0 and al,al
4107 000017B3 7410 jz .longrun
4108 000017B5 88C3 mov bl,al
4109 .dorun:
4110 000017B7 51 push cx
4111 000017B8 89D9 mov cx,bx
4112 000017BA 88D0 mov al,dl
4113 000017BC F3AA rep stosb
4114 000017BE 59 pop cx
4115 000017BF 29D9 sub cx,bx
4116 000017C1 77D5 ja .loop
4117 000017C3 EBE0 jmp short .done
4118 .longrun:
4119 000017C5 E81200 call .getnybble
4120 000017C8 88C4 mov ah,al
4121 000017CA E80D00 call .getnybble
4122 000017CD C0E004 shl al,4
4123 000017D0 08E0 or al,ah
4124 000017D2 88C3 mov bl,al
4125 000017D4 81C31000 add bx,16
4126 000017D8 EBDD jmp short .dorun
4127 .getnybble:
4128 000017DA 66D1EE shr esi,1
4129 000017DD 64AC fs lodsb
4130 000017DF 7208 jc .high
4131 000017E1 4E dec si
4132 000017E2 240F and al,0Fh
4133 000017E4 F9 stc
4134 000017E5 66D1D6 rcl esi,1
4135 000017E8 C3 ret
4136 .high:
4137 000017E9 C0E804 shr al,4
4138 000017EC 81FE0080 cmp si,xbs_vgabuf+trackbufsize ; Chunk overrun
4139 000017F0 7206 jb .nonewchunk
4140 000017F2 E80700 call vgagetchunk
4141 000017F5 BE0040 mov si,xbs_vgabuf ; Start at beginning of buffer
4142 .nonewchunk:
4143 000017F8 66D1E6 shl esi,1
4144 000017FB C3 ret
4145
4146 ;
4147 ; vgagetchunk:
4148 ; Get a new trackbufsize chunk of VGA image data
4149 ;
4150 ; On input, ES is assumed to point to the buffer segment.
4151 ;
4152 vgagetchunk:
4153 000017FC 6660 pushad
4154 000017FE 8B363855 mov si,[VGACluster]
4155 00001802 21F6 and si,si
4156 00001804 7412 jz .eof ; EOF overrun, not much to do...
4157
4158 00001806 8B0E1055 mov cx,[BufSafe] ; One trackbuf worth of data
4159 0000180A BB0040 mov bx,xbs_vgabuf
4160 0000180D E816EB call getfssec
4161
4162 00001810 7302 jnc .noteof
4163 00001812 31F6 xor si,si
4164 00001814 89363855 .noteof: mov [VGACluster],si
4165
4166 00001818 6661 .eof: popad
4167 0000181A C3 ret
4168
4169 ;
4170 ; packedpixel2vga:
4171 ; Convert packed-pixel to VGA bitplanes
4172 ;
4173 ; FS:SI -> packed pixel string
4174 ; BP -> pixel count (multiple of 8)
4175 ; ES:DI -> output
4176 ;
4177 packedpixel2vga:
4178 0000181B BAC403 mov dx,3C4h ; VGA Sequencer Register select port
4179 0000181E B002 mov al,2 ; Sequencer mask
4180 00001820 EE out dx,al ; Select the sequencer mask
4181 00001821 42 inc dx ; VGA Sequencer Register data port
4182 00001822 B001 mov al,1
4183 00001824 88C3 mov bl,al
4184 .planeloop:
4185 00001826 60 pusha
4186 00001827 EE out dx,al
4187 .loop1:
4188 00001828 B90800 mov cx,8
4189 .loop2:
4190 0000182B 87CB xchg cx,bx
4191 0000182D 64AC fs lodsb
4192 0000182F D2E8 shr al,cl
4193 00001831 D0D5 rcl ch,1 ; VGA is bigendian. Sigh.
4194 00001833 87CB xchg cx,bx
4195 00001835 E2F4 loop .loop2
4196 00001837 88F8 mov al,bh
4197 00001839 AA stosb
4198 0000183A 83ED08 sub bp,byte 8
4199 0000183D 77E9 ja .loop1
4200 0000183F 61 popa
4201 00001840 FEC3 inc bl
4202 00001842 D0E0 shl al,1
4203 00001844 80FB04 cmp bl,4
4204 00001847 76DD jbe .planeloop
4205 00001849 C3 ret
4206
4207 ;
4208 ; vgasetmode:
4209 ; Enable VGA graphics, if possible; return ZF=1 on success
4210 ; DS must be set to the base segment; ES is set to DS.
4211 ;
4212 vgasetmode:
4213 0000184A 1E push ds
4214 0000184B 07 pop es
4215 0000184C B8001A mov ax,1A00h ; Get video card and monitor
4216 0000184F 31DB xor bx,bx
4217 00001851 CD10 int 10h
4218 00001853 80FB08 cmp bl, 8 ; If not VGA card/VGA monitor, give up
4219 00001856 751C jne .error ; ZF=0
4220 ; mov bx,TextColorReg
4221 ; mov dx,1009h ; Read color registers
4222 ; int 10h
4223 00001858 B81200 mov ax,0012h ; Set mode = 640x480 VGA 16 colors
4224 0000185B CD10 int 10h
4225 0000185D BA[BB18] mov dx,linear_color
4226 00001860 B80210 mov ax,1002h ; Write color registers
4227 00001863 CD10 int 10h
4228 00001865 C606[CC18]01 mov [UsingVGA], byte 1
4229
4230 0000186A E802F9 call use_font ; Set graphics font/data
4231 0000186D C606[7B1D]00 mov byte [ScrollAttribute], 00h
4232
4233 00001872 31C0 xor ax,ax ; Set ZF
4234 .error:
4235 00001874 C3 ret
4236
4237 ;
4238 ; vgaclearmode:
4239 ; Disable VGA graphics. It is not safe to assume any value
4240 ; for DS or ES.
4241 ;
4242 vgaclearmode:
4243 00001875 1E push ds
4244 00001876 06 push es
4245 00001877 6660 pushad
4246 00001879 8CC8 mov ax,cs
4247 0000187B 8ED8 mov ds,ax
4248 0000187D 8EC0 mov es,ax
4249 0000187F 803E[CC18]01 cmp [UsingVGA], byte 1
4250 00001884 7512 jne .done
4251 00001886 B80300 mov ax,0003h ; Return to normal video mode
4252 00001889 CD10 int 10h
4253 ; mov dx,TextColorReg ; Restore color registers
4254 ; mov ax,1002h
4255 ; int 10h
4256 0000188B C606[CC18]00 mov [UsingVGA], byte 0
4257
4258 00001890 E8DCF8 call use_font ; Restore text font/data
4259 00001893 C606[7B1D]07 mov byte [ScrollAttribute], 07h
4260 .done:
4261 00001898 6661 popad
4262 0000189A 07 pop es
4263 0000189B 1F pop ds
4264 0000189C C3 ret
4265
4266 ;
4267 ; vgashowcursor/vgahidecursor:
4268 ; If VGA graphics is enabled, draw a cursor/clear a cursor
4269 ;
4270 vgashowcursor:
4271 0000189D 6660 pushad
4272 0000189F B05F mov al,'_'
4273 000018A1 EB04 jmp short vgacursorcommon
4274 vgahidecursor:
4275 000018A3 6660 pushad
4276 000018A5 B020 mov al,' '
4277 vgacursorcommon:
4278 000018A7 803E[CC18]01 cmp [UsingVGA], byte 1
4279 000018AC 750A jne .done
4280 000018AE B409 mov ah,09h
4281 000018B0 BB0700 mov bx,0007h
4282 000018B3 B90100 mov cx,1
4283 000018B6 CD10 int 10h
4284 .done:
4285 000018B8 6661 popad
4286 000018BA C3 ret
4287
4288
4289 ; Map colors to consecutive DAC registers
4290 000018BB 000102030405060708- linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
4291 000018C4 090A0B0C0D0E0F00
4292 000018CC 00 UsingVGA db 0
4293
4294 ; ----------------------------------------------------------------------------------
4295 ; Begin data section
4296 ; ----------------------------------------------------------------------------------
4297
4298 CR equ 13 ; Carriage Return
4299 LF equ 10 ; Line Feed
4300 FF equ 12 ; Form Feed
4301 BS equ 8 ; Backspace
4302
4303 ;
4304 ; Lower-case table for codepage 865
4305 ;
4306 lcase_low equ 128
4307 lcase_high equ 165
4308 000018CD 878182838485868788- lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
4309 000018D6 898A
4310 000018D8 8B8C8D848682919193- db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
4311 000018E1 9495
4312 000018E3 96979894819B9C9B9E- db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
4313 000018EC 9FA0
4314 000018EE A1A2A3A4A4 db 161, 162, 163, 164, 164
4315
4316 000018F3 20436F707972696768- copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
4317 000018FC 742028432920313939-
4318 00001905 342D3230303220482E-
4319 0000190E 20506574657220416E-
4320 00001917 76696E
4321 0000191A 0D0A00 db CR, LF, 0
4322 0000191D 626F6F743A2000 boot_prompt db 'boot: ', 0
4323 00001924 08200800 wipe_char db BS, ' ', BS, 0
4324 00001928 436F756C64206E6F74- err_notfound db 'Could not find kernel image: ',0
4325 00001931 2066696E64206B6572-
4326 0000193A 6E656C20696D616765-
4327 00001943 3A2000
4328 00001946 0D0A496E76616C6964- err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
4329 0000194F 206F7220636F727275-
4330 00001958 7074206B65726E656C-
4331 00001961 20696D6167652E0D0A-
4332 0000196A 00
4333 0000196B 497420617070656172- err_not386 db 'It appears your computer uses a 286 or lower CPU.'
4334 00001974 7320796F757220636F-
4335 0000197D 6D7075746572207573-
4336 00001986 657320612032383620-
4337 0000198F 6F72206C6F77657220-
4338 00001998 4350552E
4339 0000199C 0D0A db CR, LF
4340 0000199E 596F752063616E6E6F- db 'You cannot run Linux unless you have a 386 or higher CPU'
4341 000019A7 742072756E204C696E-
4342 000019B0 757820756E6C657373-
4343 000019B9 20796F752068617665-
4344 000019C2 206120333836206F72-
4345 000019CB 206869676865722043-
4346 000019D4 5055
4347 000019D6 0D0A db CR, LF
4348 000019D8 696E20796F7572206D- db 'in your machine. If you get this message in error, hold'
4349 000019E1 616368696E652E2020-
4350 000019EA 496620796F75206765-
4351 000019F3 742074686973206D65-
4352 000019FC 737361676520696E20-
4353 00001A05 6572726F722C20686F-
4354 00001A0E 6C64
4355 00001A10 0D0A db CR, LF
4356 00001A12 646F776E2074686520- db 'down the Ctrl key while booting, and I will take your'
4357 00001A1B 4374726C206B657920-
4358 00001A24 7768696C6520626F6F-
4359 00001A2D 74696E672C20616E64-
4360 00001A36 20492077696C6C2074-
4361 00001A3F 616B6520796F7572
4362 00001A47 0D0A db CR, LF
4363 00001A49 776F726420666F7220- db 'word for it.', CR, LF, 0
4364 00001A52 69742E0D0A00
4365 00001A58 497420617070656172- err_noram db 'It appears your computer has less than 512K of low ("DOS")'
4366 00001A61 7320796F757220636F-
4367 00001A6A 6D7075746572206861-
4368 00001A73 73206C657373207468-
4369 00001A7C 616E203531324B206F-
4370 00001A85 66206C6F7720282244-
4371 00001A8E 4F532229
4372 00001A92 0D0A db CR, LF
4373 00001A94 52414D2E20204C696E- db 'RAM. Linux needs at least this amount to boot. If you get'
4374 00001A9D 7578206E6565647320-
4375 00001AA6 6174206C6561737420-
4376 00001AAF 7468697320616D6F75-
4377 00001AB8 6E7420746F20626F6F-
4378 00001AC1 742E2020496620796F-
4379 00001ACA 7520676574
4380 00001ACF 0D0A db CR, LF
4381 00001AD1 74686973206D657373- db 'this message in error, hold down the Ctrl key while'
4382 00001ADA 61676520696E206572-
4383 00001AE3 726F722C20686F6C64-
4384 00001AEC 20646F776E20746865-
4385 00001AF5 204374726C206B6579-
4386 00001AFE 207768696C65
4387 00001B04 0D0A db CR, LF
4388 00001B06 626F6F74696E672C20- db 'booting, and I will take your word for it.', CR, LF, 0
4389 00001B0F 616E6420492077696C-
4390 00001B18 6C2074616B6520796F-
4391 00001B21 757220776F72642066-
4392 00001B2A 6F722069742E0D0A00
4393 00001B33 556E6B6E6F776E206B- err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
4394 00001B3C 6579776F726420696E-
4395 00001B45 207379736C696E7578-
4396 00001B4E 2E6366672E0D0A00
4397 00001B56 4D697373696E672070- err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
4398 00001B5F 6172616D6574657220-
4399 00001B68 696E207379736C696E-
4400 00001B71 75782E6366672E0D0A-
4401 00001B7A 00
4402 00001B7B 0D0A436F756C64206E- err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
4403 00001B84 6F742066696E642072-
4404 00001B8D 616D6469736B20696D-
4405 00001B96 6167653A2000
4406 00001B9C 4E6F7420656E6F7567- err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
4407 00001BA5 68206D656D6F727920-
4408 00001BAE 746F206C6F61642073-
4409 00001BB7 706563696669656420-
4410 00001BC0 6B65726E656C2E0D0A-
4411 00001BC9 00
4412 00001BCA 0D0A4B65726E656C20- err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
4413 00001BD3 7472616E7366657220-
4414 00001BDC 6661696C7572652E0D-
4415 00001BE5 0A00
4416 00001BE7 43616E6E6F74206C6F- err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
4417 00001BF0 616420612072616D64-
4418 00001BF9 69736B207769746820-
4419 00001C02 616E206F6C64206B65-
4420 00001C0B 726E656C20696D6167-
4421 00001C14 652E
4422 00001C16 0D0A00 db CR, LF, 0
4423 00001C19 3A20617474656D7074- err_notdos db ': attempted DOS system call', CR, LF, 0
4424 00001C22 656420444F53207379-
4425 00001C2B 7374656D2063616C6C-
4426 00001C34 0D0A00
4427 00001C37 434F4D424F4F542069- err_comlarge db 'COMBOOT image too large.', CR, LF, 0
4428 00001C40 6D61676520746F6F20-
4429 00001C49 6C617267652E0D0A00
4430 00001C52 496E76616C6964206F- err_bootsec db 'Invalid or corrupt boot sector image.', CR, LF, 0
4431 00001C5B 7220636F7272757074-
4432 00001C64 20626F6F7420736563-
4433 00001C6D 746F7220696D616765-
4434 00001C76 2E0D0A00
4435 00001C7A 0D0A41323020676174- err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
4436 00001C83 65206E6F7420726573-
4437 00001C8C 706F6E64696E67210D-
4438 00001C95 0A00
4439 00001C97 0D0A426F6F74206661- err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
4440 00001CA0 696C65643A20706C65-
4441 00001CA9 617365206368616E67-
4442 00001CB2 65206469736B732061-
4443 00001CBB 6E6420707265737320
4444 00001CC4 61206B657920746F20- db 'a key to continue.', CR, LF, 0
4445 00001CCD 636F6E74696E75652E-
4446 00001CD6 0D0A00
4447 00001CD9 2072656164792E0D0A- ready_msg db ' ready.', CR, LF, 0
4448 00001CE2 00
4449 00001CE3 4C6F6164696E672000 loading_msg db 'Loading ', 0
4450 00001CEC 2E dotdot_msg db '.'
4451 00001CED 2E00 dot_msg db '.', 0
4452 00001CEF 2061626F727465642E aborted_msg db ' aborted.' ; Fall through to crlf_msg!
4453 00001CF8 0D0A00 crlf_msg db CR, LF, 0
4454 00001CFB 0D0C00 crff_msg db CR, FF, 0
4455 00001CFE 5359534C494E555843- syslinux_cfg db 'SYSLINUXCFG'
4456 00001D07 4647
4457 ;
4458 ; Command line options we'd like to take a look at
4459 ;
4460 ; mem= and vga= are handled as normal 32-bit integer values
4461 00001D09 696E697472643D initrd_cmd db 'initrd='
4462 initrd_cmd_len equ 7
4463 ;
4464 ; Config file keyword table
4465 ;
4466 align 2
4467 00001D10 6170 keywd_table db 'ap' ; append
4468 00001D12 6465 db 'de' ; default
4469 00001D14 7469 db 'ti' ; timeout
4470 00001D16 666F db 'fo' ; font
4471 00001D18 6B62 db 'kb' ; kbd
4472 00001D1A 6469 db 'di' ; display
4473 00001D1C 7072 db 'pr' ; prompt
4474 00001D1E 6C61 db 'la' ; label
4475 00001D20 696D db 'im' ; implicit
4476 00001D22 6B65 db 'ke' ; kernel
4477 00001D24 7365 db 'se' ; serial
4478 00001D26 6631 db 'f1' ; F1
4479 00001D28 6632 db 'f2' ; F2
4480 00001D2A 6633 db 'f3' ; F3
4481 00001D2C 6634 db 'f4' ; F4
4482 00001D2E 6635 db 'f5' ; F5
4483 00001D30 6636 db 'f6' ; F6
4484 00001D32 6637 db 'f7' ; F7
4485 00001D34 6638 db 'f8' ; F8
4486 00001D36 6639 db 'f9' ; F9
4487 00001D38 6630 db 'f0' ; F10
4488 00001D3A 0000 dw 0
4489 ;
4490 ; Extensions to search for (in *reverse* order). Note that the last
4491 ; (lexically first) entry in the table is a placeholder for the original
4492 ; extension, needed for error messages. The exten_table is shifted so
4493 ; the table is 1-based; this is because a "loop" cx is used as index.
4494 ;
4495 exten_table:
4496 00001D3C 00000000 OrigKernelExt: dd 0 ; Original extension
4497 00001D40 434F4D00 db 'COM',0 ; COMBOOT (same as DOS)
4498 00001D44 42532000 db 'BS ',0 ; Boot Sector
4499 00001D48 42535300 db 'BSS',0 ; Boot Sector (add superblock)
4500 00001D4C 43425400 db 'CBT',0 ; COMBOOT (specific)
4501
4502 exten_count equ (($-exten_table) >> 2) - 1 ; Number of alternates
4503 ;
4504 ; Misc initialized (data) variables
4505 ;
4506 %ifdef debug ; This code for debugging only
4507 debug_magic dw 0D00Dh ; Debug code sentinel
4508 %endif
4509 00001D50 0000 AppendLen dw 0 ; Bytes in append= command
4510 00001D52 0000 KbdTimeOut dw 0 ; Keyboard timeout (if any)
4511 00001D54 0000 FKeyMap dw 0 ; Bitmap for F-keys loaded
4512 00001D56 0090 CmdLinePtr dw cmd_line_here ; Command line advancing pointer
4513 initrd_flag equ $
4514 00001D58 0000 initrd_ptr dw 0 ; Initial ramdisk pointer/flag
4515 00001D5A 0000 VKernelCtr dw 0 ; Number of registered vkernels
4516 00001D5C 0000 ForcePrompt dw 0 ; Force prompt
4517 00001D5E 0100 AllowImplicit dw 1 ; Allow implicit kernels
4518 00001D60 0000 SerialPort dw 0 ; Serial port base (or 0 for no serial port)
4519 00001D62 [170F][170F][220F]- A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
4520 00001D68 [340F][5A0F]
4521 00001D6C [E20F][E20F][B40F]- A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
4522 00001D72 [C50F][BD0F]
4523 00001D76 0000 A20Type dw A20_DUNNO ; A20 type unknown
4524 00001D78 1000 VGAFontSize dw 16 ; Defaults to 16 byte font
4525 00001D7A 00 UserFont db 0 ; Using a user-specified font
4526 00001D7B 07 ScrollAttribute db 07h ; White on black (for text mode)
4527 ;
4528 ; Stuff for the command line; we do some trickery here with equ to avoid
4529 ; tons of zeros appended to our file and wasting space
4530 ;
4531 00001D7C 6C696E757820617574- linuxauto_cmd db 'linux auto',0
4532 00001D85 6F00
4533 linuxauto_len equ $-linuxauto_cmd
4534 00001D87 424F4F545F494D4147- boot_image db 'BOOT_IMAGE='
4535 00001D90 453D
4536 boot_image_len equ $-boot_image
4537 00001D92 00<rept> align 4, db 0 ; For the good of REP MOVSD
4538 command_line equ $
4539 default_cmd equ $+(max_cmd_len+2)
4540 ldlinux_end equ default_cmd+(max_cmd_len+1)
4541 kern_cmd_len equ ldlinux_end-command_line
4542 ldlinux_len equ ldlinux_end-ldlinux_magic
4543 ;
4544 ; Put the getcbuf right after the code, aligned on a sector boundary
4545 ;
4546 end_of_code equ (ldlinux_end-bootsec)+7C00h
4547 getcbuf equ (end_of_code + 511) & 0FE00h
4548
4549 ; VGA font buffer at the end of memory (so loading a font works even
4550 ; in graphics mode.)
4551 vgafontbuf equ 0E000h
4552
4553 ; This is a compile-time assert that we didn't run out of space
4554 %if (getcbuf+trackbufsize) > vgafontbuf
4555 %error "Out of memory, better reorganize something..."
4556 %endif
|