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
|
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sgabios.h"
#define BUILD_CL "$Id: sgabios.S 8 2010-04-22 00:03:40Z nlaredo $"
.code16
.text
.section ".init","ax"
.globl _start
.type _start,@object
_start:
/* option rom header */
.byte 0x55
.byte 0xaa
.byte _rom_size_byte
.size _start, .-_start
.globl legacy_entry
.type legacy_entry,@function
legacy_entry:
jmp sga_init
/* pnp entry here to avoid changing PnP table as code moves */
pnp_init:
jmp pnp_sga_init
/*
* do_old_int10h
*
* Patched at option rom init to be a far jump to old int 10h isr
*
*/
do_old_int10h:
.byte 0xea /* jmp absolute segment:offset */
old_int10h: /* store what was at offset 0x40 */
.word 0xf065 /* placeholder for chained ISR offset */
/* if the chained segment is detected as 0xc000, use 80 cols only */
/* since it's assumed that a vga card is attached and 80 cols max */
old_int10h_seg:
.word 0xf000 /* placeholder for chained ISR segment */
/*
* do_old_int16h
*
* Patched at option rom init to be a far jump to old int 16h isr
*
*/
do_old_int16h:
.byte 0xea /* jmp absolute segment:offset */
old_int16h: /* store what was at offset 0x58 */
.word 0xe82e /* placeholder for chained ISR offset */
.word 0xf000 /* placeholder for chained ISR segment */
.org 0x18
.word 0 /* offset to PCI data, 0 = none */
.word pnp_table /* offset to PnP expansion header */
.org 0x20
pnp_table:
/* FIXME: **** PnP header currently disabled by PoO **** */
/* legacy entry only called once, PnP entry called multiple times */
/* The code isn't yet written to deal with multiple inits properly */
.ascii "$PoO" /* PnP expansion header signature */
.byte 1 /* structure revision */
.byte 2 /* length in 16-byte increments */
.word 0 /* offset of next header, 0 if none */
.byte 0 /* reserved */
.byte 0x52 /* checksum - update manually! FIXME */
.long 0 /* device identifier */
.word mfg_string /* pointer to manufacturer string */
.word prod_string /* pointer to product name string */
.byte 3, 0x80, 0x80 /* device type code = other display */
.byte 0xe3 /* device indicators, kbd/display dev */
.word 0 /* boot connection vector, 0 if none */
.word 0 /* disconnect vector, 0 if none */
.word pnp_init /* bootstrap entry vector */
.word 0 /* reserved */
.word 0 /* static resource information vector */
/* WARNING: changing mfg_string / prod_string locations will */
/* affect pnp table above -- recalculate checksum manually! */
mfg_string:
.asciz "Google, Inc."
prod_string:
.ascii "Serial Graphics Adapter "
build_date:
.asciz BUILD_SHORT_DATE
long_version:
.ascii "SGABIOS "
.ascii BUILD_CL
.ascii " ("
.ascii BUILD_USER
.ascii "@"
.ascii BUILD_HOST
.ascii ") "
.asciz BUILD_DATE
term_cols:
.byte 80 /* overwritten at rom init with detected value */
term_rows:
.byte 24 /* overwritten at rom init with detected value */
term_init_string: /* terminal reply: \033[n;mR n=row, m=col */
.asciz "\033[1;256r\033[256;256H\033[6n"
/* reset the scroll, move to col 256, row 256, ask current position */
/* bios cursor positions >255 rows or cols can't be used anyway */
term_info:
.asciz "Term: "
ebda_info:
.asciz "EBDA: "
/*
* do_old_irq3 - exception 0x0b, int 0x0a
*
* Patched at option rom init to be a far jump to old irq 3 isr
*
*/
do_old_irq3:
.byte 0xea /* jmp absolute segment:offset */
old_irq3: /* store what was at offset 0x28 */
.word 0xeef3 /* placeholder for chained ISR offset */
.word 0xf000 /* placeholder for chained ISR segment */
/*
* do_old_irq4 - exception 0x0c, int 0x0b
*
* Patched at option rom init to be a far jump to old irq 4 isr
*
*/
do_old_irq4:
.byte 0xea /* jmp absolute segment:offset */
old_irq4: /* store what was at offset 0x2c */
.word 0xeef3 /* placeholder for chained ISR offset */
.word 0xf000 /* placeholder for chained ISR segment */
/*
* do_old_int14h
*
* Patched at option rom init to be a far jump to old int 14h isr
*
*/
do_old_int14h:
.byte 0xea /* jmp absolute segment:offset */
old_int14h: /* store what was at offset 0x50 */
.word 0xe739 /* placeholder for chained ISR offset */
.word 0xf000 /* placeholder for chained ISR segment */
.align 16, 0xff /* aligning this table only makes hexdump prettier */
/* ascii -> scancode, bit 7=shifted, char < 32 = +ctrl */
/* except chars 8, 9, 13, 27 (bs, tab, enter, esc) */
/* most int16h consumers will probably never use */
ascii2scan:
/*00*/ .byte 0x00, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22
/*08*/ .byte 0x0e, 0x17, 0x24, 0x25, 0x26, 0x1c, 0x31, 0x18
/*10*/ .byte 0x19, 0x0f, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11
/*18*/ .byte 0x2d, 0x15, 0x2c, 0x01, 0x2b, 0x1b, 0x87, 0x8c
/*20*/ .byte 0x39, 0x82, 0xa8, 0x84, 0x85, 0x86, 0x88, 0x28
/*28*/ .byte 0x8a, 0x8b, 0x89, 0x8d, 0x33, 0x0c, 0x34, 0x35
/*30*/ .byte 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
/*38*/ .byte 0x09, 0x0a, 0xa7, 0x27, 0xb3, 0x0d, 0x34, 0xb5
/*40*/ .byte 0x83, 0x9e, 0xb0, 0xae, 0xa0, 0x92, 0xa1, 0xa2
/*48*/ .byte 0xa3, 0x97, 0xa4, 0xa5, 0xa6, 0xb2, 0xb1, 0x98
/*50*/ .byte 0x99, 0x90, 0x93, 0x9f, 0x94, 0x96, 0xaf, 0x91
/*58*/ .byte 0xad, 0x95, 0xac, 0x1a, 0x2b, 0x1b, 0x87, 0x8c
/*60*/ .byte 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22
/*68*/ .byte 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18
/*70*/ .byte 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11
/*78*/ .byte 0x2d, 0x15, 0x2c, 0x9a, 0xab, 0x9b, 0xa9, 0x0e
/* TABLES FOR NON-ASCII VGA CHARACTERS (CP437) TO ASCII */
/* Unicode at: http://en.wikipedia.org/wiki/Code_page_437 */
ctrl2ascii:
/* translate vga (CP437) first 32 characters to ascii */
/* for char 0, update the cursor position, but output nothing */
/* lilo uses this "trick" for a background attribute update */
.ascii "\0@@v***........*><|!PS-|^v><L-^v"
high2ascii:
/* translate vga (CP437) chars 0x80 to 0xff to ascii */
/* these characters are mostly to visually approximate */
/* line art characters will probably need tweaking */
/*80*/ .ascii "CueaaaaceeeiiiAAEaAooouuyOUcLYPf"
/*a0*/ .ascii "aiounNao?--24!<>###||||++||+++++"
/*c0*/ .ascii "+--|-+||++--|-+----++++++++#-||-"
/*e0*/ .ascii "abgpesut00osiye^=+><||-=...vn2* "
colortable:
/* vga text color is IRGB, ansi color is BGR */
/* this table is effectively a nibble bit-reverse */
.byte 0, 4, 2, 6, 1, 5, 3, 7
serial_port_base_address:
.word COM_BASE_ADDR
/* in-memory console log
*
* It's expected that the EBDA contains a magic signature
* like 0xdeadbabe, followed by a byte of flags, followed
* by a 32-bit buffer pointer, followed by a 16-bit start
* index, followed by a 16-bit end index, followed by 16-
* bit logged character count, followed by an 8-bit flag.
*/
#define MEMCONSOLE_BUFFER_SIZE 32768
#define MEMCONSOLE_SIGNATURE 0xdeadbabe
#define MEMCONSOLE_ENDINDEX_OFF 0x0b
#define SGABIOS_EBDA_SIGNATURE 0x00414753
memconsole_buffer_start: /* pulled from ebda struct */
.long 0x00000000 /* 0 = not found/no logging */
memconsole_ebda_deadbabe_offset: /* bytes from start of ebda */
.word 0x0000 /* 40:0e contains ebda seg */
sgabios_ebda_logbuf_offset: /* bytes from start of ebda */
.word 0x0000 /* 40:0e contains ebda seg */
/*
* setup_memconsole
*
* Initialize the option rom variables associated with logging
* of the legacy console output
*
* If these variables are left at zero, no logging will occur
*
* There are no parameters
* All registers except flags should be preserved
*/
setup_memconsole:
pushaw
pushw %ds
pushw %es
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
pushw BDA_EBDA /* push word at 0x0e */
popw %es /* es = EBDA_SEG */
/* search for memconsole signature in ebda */
movl $MEMCONSOLE_SIGNATURE, %eax
xorw %di, %di /* start at zero */
movzbw %es:(%di), %cx /* cx = size of EBDA in KB */
shlw $8, %cx /* cx = (cx * 1024) / 4 */
cld
repnz
scasl /* search until sig found */
subw $4, %di /* scasl always increments di, undo */
cmpl %eax, %es:(%di) /* is signature here? */
jnz setup_memconsole_end /* bail if so */
movw %di, %cs:memconsole_ebda_deadbabe_offset /* save offset */
movl %es:5(%di), %eax /* get 32-bit buffer base address */
movl %eax, %cs:memconsole_buffer_start
setup_memconsole_end:
popw %es
popw %ds
popaw
ret
/*
* memconsole_log_char
*
* Log the character passed in %al to the next available memory
* console log position, if any.
*
* If memconsole_buffer_start is zero, no logging will occur
*
* %al = character to be logged
* All registers except flags should be preserved
*/
memconsole_log_char:
pushaw
pushw %ds
pushw %es
pushw %fs
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
pushw BDA_EBDA /* push word at 0x0e */
popw %es /* es = EBDA_SEG */
movw %ax, %si /* %si = %al = byte to write */
movl %cs:memconsole_buffer_start, %ebp
movw %cs:memconsole_ebda_deadbabe_offset, %di
addw $MEMCONSOLE_ENDINDEX_OFF, %di /* %di points to char pos */
orl %ebp, %ebp
jz memconsole_log_tail /* bufptr==0, no logging */
movw %es:(%di), %bx /* bx = current position in buffer */
cmpw $MEMCONSOLE_BUFFER_SIZE, %bx /* at end of buffer? */
jnc memconsole_log_tail /* don't log any more if so */
cmpb $0xd, %al /* is the char CR? */
jz memconsole_log_tail /* if so, ignore it */
cmpb $0x8, %al /* is the char backspace? */
jnz memconsole_update_fsbase /* if not, log char as usual... */
orw %bx, %bx /* make sure ptr isn't already zero */
jz memconsole_log_tail /* if so, bail */
decw %bx /* else point to previous character */
jmp memconsole_update_end_ptr /* and go directly to save it */
memconsole_update_fsbase:
movl $0xc0000100, %ecx /* ecx = IA32_FS_BASE (AMD64+) */
rdmsr /* read what was there before */
pushl %eax /* save away previous FS_BASE eax */
pushl %edx /* save away previous FS_BASE edx */
xorl %edx, %edx /* clear high 32 bits */
movl %ebp, %eax /* eax = memconsole buffer start */
wrmsr /* fs_base = memconsole buffer start */
movw %si, %ax /* %ax = saved value on entry */
movb %al, %fs:(%bx) /* log character */
popl %edx /* restore previous FS_BASE edx */
popl %eax /* restore previous FS_BASE eax */
wrmsr /* write what was there before */
incw %bx /* update character count */
memconsole_update_end_ptr:
movw %bx, %es:(%di) /* save new end pointer */
addw $2, %di /* numchars stored at next word */
movw %bx, %es:(%di) /* save new numchar value */
memconsole_log_tail:
popw %fs
popw %es
popw %ds
popaw
ret
/* sgabioslog_setup_ebda
*
* SGABIOS makes its own 1KB EBDA allocation to save non-
* translated characters with associated cursor positions
* for the last 256 characters output. This is organized
* with 256 bytes reserved for houskeeping, 256 bytes for
* the raw character codes, and 512 bytes of 16bit cursor
* positions to record the associated position for each.
*
* The first 4 bytes contain "SGA\0" followed by a 16-bit
* size of the allocation in bytes, followed by a 16-bit
* index indicating the next spot to be overwritten.
*
* There are no parameters
* All registers should be preserved
*/
sgabioslog_setup_ebda:
pushf
pushaw
pushw %ds
pushw %es
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movw BDA_EBDA, %ax /* ax = old ebda segment from 0x0e */
subw $SGABIOS_EBDA_DELTA, %ax
movw %ax, %es /* es = new EBDA segment start */
cmpw $EBDA_MIN_SEG, %ax /* is there room for the allocation? */
jc sgabioslog_setup_ebda_tail /* if not, don't change anything */
cli /* paranoid in case irq uses EBDA */
movw %ax, BDA_EBDA /* save new EBDA segment start */
subw $SGABIOS_EBDA_KB, BDA_MEM_SIZE /* subtract extra allocation */
movw %ax, %ds /* ds = new EBDA segment start */
movw $SGABIOS_EBDA_BYTES, %si /* si = offset of first byte to move */
movzbw (%si), %cx /* cx = number of KB in EBDA */
addb $SGABIOS_EBDA_KB, (%si) /* update EBDA size in kb */
shlw $10, %cx /* cx = KB * 1024 = bytes in EBDA */
movw %cx, %cs:sgabios_ebda_logbuf_offset /* new ebda space */
xorw %di, %di /* di = new EBDA start */
cld
rep
movsb /* move ebda by SGABIOS_EBDA_BYTES */
movw %cs:sgabios_ebda_logbuf_offset, %bx /* bx = new buffer */
movl $SGABIOS_EBDA_SIGNATURE, (%bx) /* setup signature */
movw $SGABIOS_EBDA_BYTES, 4(%bx) /* bytes in new ebda buffer */
movw $0, 6(%bx) /* next log index, new ebda buffer */
sgabioslog_setup_ebda_tail:
popw %es
popw %ds
popaw
popf
ret
/*
* sgabioslog_save_char
*
* Like memconsole_log_char, except the original, untranslated
* character is expected to be given in the %al register.
*
* The original character and its corresponding cursor position
* are logged to the sgabios ebda memory allocation.
*
* %al = character to be logged
* All registers except flags should be preserved
*/
sgabioslog_save_char:
pushaw
pushw %ds
pushw %es
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
pushw BDA_EBDA /* push word at 0x0e */
popw %es /* es = EBDA_SEG */
movw %cs:sgabios_ebda_logbuf_offset, %di
orw %di, %di /* is offset zero? */
jz sgabioslog_save_tail /* if so, bail */
cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di)
jnz sgabioslog_save_tail /* bail if magic not found */
movw %es:6(%di), %bx /* bx = index of next char output */
movb %al, %es:SGABIOS_EBDA_LOG_START(%bx,%di) /* store character */
movzbw %bl, %ax /* %ax = next cursor buffer index */
shlw $1, %ax /* %ax = offset to cursor storage */
call get_current_cursor /* %dh = row, %dl = column */
addw $SGABIOS_EBDA_POS_START, %di /* cursor storage */
addw %ax, %di /* %di = next cursor storage offset */
movw %dx, %es:(%di) /* save position for logged char */
incw %bx /* point to next char to log */
cmpw $SGABIOS_EBDA_LOG_SIZE, %bx
jnz sgabioslog_save_index
xorw %bx, %bx /* wrap around to start */
sgabioslog_save_index:
movw %cs:sgabios_ebda_logbuf_offset, %di
movw %bx, %es:6(%di) /* save new index */
sgabioslog_save_tail:
popw %es
popw %ds
popaw
ret
/*
* sgabioslog_get_char
*
* Return the character at current cursor position, last recorded
* to sgabios ebda allocation, if available.
*
* If the current cursor postition contains one of the last 256 characters
* written to the ebda buffer, return that character, else return 0.
*
* If sgabios_ebdda_logbuf_offset is zero, %al will be 0 and zf set
*
* All registers except flags and %al should be preserved
*/
sgabioslog_get_char:
pushaw
movw %sp, %bp
movb $0, 14(%bp) /* %al on stack = 0 */
pushw %ds
pushw %es
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
pushw BDA_EBDA /* push word at 0x0e */
popw %es /* es = EBDA_SEG */
movw %cs:sgabios_ebda_logbuf_offset, %di
orw %di, %di
jz sgabioslog_get_tail /* offset==0, no logging */
cmpl $SGABIOS_EBDA_SIGNATURE, %es:(%di)
jnz sgabioslog_get_tail /* bail if magic not found */
call get_current_cursor /* dh = row, dl = col */
std /* scan backwards in mem */
movw %es:6(%di), %bx /* bx = index of next char output */
decw %bx /* %bx = offset of last char in buf */
jnc sgabioslog_got_pos
addw $SGABIOS_EBDA_LOG_SIZE, %bx /* bx position wrap around */
sgabioslog_got_pos:
movw %bx, %ax /* %ax = last cursor pos written */
shlw $1, %ax /* %ax = offset of last cursor pos */
addw $SGABIOS_EBDA_POS_START, %di /* %di = first cursor position */
addw %ax, %di /* %di = offset in ebda */
movw %dx, %ax /* %ax = cursor pos to compare */
movw %bx, %cx /* %cx = positions before wrap */
jcxz sgabioslog_cmp_wrap /* if zero, try from end next */
repnz
scasw /* search until position match */
addw $2, %di /* scasd always decrements di, undo */
cmpw %ax, %es:(%di) /* did it really match? */
jz sgabioslog_cursor_match /* if so, do something */
sgabioslog_cmp_wrap:
movw %cs:sgabios_ebda_logbuf_offset, %di
addw $SGABIOS_EBDA_POS_LAST, %di /* %di = last cursor storage */
movw $SGABIOS_EBDA_LOG_SIZE, %cx /* %cx = compare all positions */
repnz
scasw /* search until position match */
addw $2, %di /* scasd always decrements di, undo */
cmpw %ax, %es:(%di) /* did it really match? */
jnz sgabioslog_get_tail /* if not, bail */
sgabioslog_cursor_match:
/* %di contains the EBDA offset of the matching position */
/* convert this into a memconsole offset */
subw $512, %di /* take off the storage offset */
subw %cs:sgabios_ebda_logbuf_offset, %di /* and ebda offset */
shrw $1, %di /* %di = char position index */
addw %cs:sgabios_ebda_logbuf_offset, %di /* add back ebda offset */
addw $SGABIOS_EBDA_LOG_START, %di /* and add back log offset */
movb %es:(%di), %al /* get related saved character */
movb %al, 14(%bp) /* %al on stack = logged char */
sgabioslog_get_tail:
popw %es
popw %ds
popaw
ret
/*
* multibyteinput
*
* When an escape key is detected, the input routines will attempt to
* capture as many characters as arrive up until a timeout, or six,
* whichever is less.
*
* This table is intended to decide what the characters after the
* initial escape key translate to in terms of high and low bytes
* that go into the keyboard buffer the high byte is the scancode,
* the low byte is ascii, but for special keys this is usually 0xe0
* or 0x00.
*
* This table is formatted so that the first word is a scancode +
* ascii pair (as returned by int 16h, ah = 10h or 11h). Immediately
* following is a nul-terminated ascii string to match in order to
* use the corresponding scancode+ascii word.
*
* The search through this table is terminated by a match or finding
* a 0 scancode+ascii word.
*
* FIXME: all the low bytes are now zero, get rid of them?
*/
multibyteinput:
.byte 0x3b /* F1 */
.asciz "[[A" /* F1/screen */
.byte 0x3b /* F1 */
.asciz "OP" /* F1/xterm/ansi */
.byte 0x3b /* F1 */
.asciz "[11~" /* F1/vt400 */
.byte 0x3c /* F2 */
.asciz "[[B" /* F2/screen */
.byte 0x3c /* F2 */
.asciz "OQ" /* F2/xterm/ansi */
.byte 0x3c /* F2 */
.asciz "[12~" /* F2/vt400 */
.byte 0x3d /* F3 */
.asciz "[[C" /* F3/screen */
.byte 0x3d /* F3 */
.asciz "OR" /* F3/xterm/ansi */
.byte 0x3d /* F3 */
.asciz "[13~" /* F3/vt400 */
.byte 0x3e /* F4 */
.asciz "[[D" /* F4/screen */
.byte 0x3e /* F4 */
.asciz "OS" /* F4/xterm/ansi */
.byte 0x3e /* F4 */
.asciz "[14~" /* F4/vt400 */
.byte 0x3f /* F5 */
.asciz "[[E" /* F5/screen */
.byte 0x3f /* F5 */
.asciz "[15~" /* F5/xterm */
.byte 0x3f /* F5 */
.asciz "OT" /* F5/ansi */
.byte 0x40 /* F6 */
.asciz "[17~" /* F6/screen/vt220/xterm/vt400 */
.byte 0x40 /* F6 */
.asciz "OU" /* F6/ansi */
.byte 0x41 /* F7 */
.asciz "[18~" /* F7/screen/vt220/xterm/vt400 */
.byte 0x41 /* F7 */
.asciz "OV" /* F7/ansi */
.byte 0x42 /* F8 */
.asciz "[19~" /* F8/screen/vt220/xterm/vt400 */
.byte 0x42 /* F8 */
.asciz "OW" /* F8/ansi */
.byte 0x43 /* F9 */
.asciz "[20~" /* F9/screen/vt220/xterm/vt400 */
.byte 0x43 /* F9 */
.asciz "OX" /* F9/ansi */
.byte 0x44 /* F10 */
.asciz "[21~" /* F10/screen/vt220/xterm/vt400 */
.byte 0x44 /* F10 */
.asciz "OY" /* F10/ansi */
.byte 0x85 /* F11 */
.asciz "[23~" /* F11/screen/xterm/vt400 */
.byte 0x85 /* F11 */
.asciz "OZ" /* F11/ansi */
.byte 0x86 /* F12 */
.asciz "[24~" /* F12/screen/xterm/vt400 */
.byte 0x52 /* Insert */
.asciz "[2~" /* Insert/screen/vt102/xterm */
.byte 0x53 /* Delete */
.asciz "[3~" /* Delete/screen/vt102/xterm */
.byte 0x4b /* Left */
.asciz "OD" /* Left/screen/vt102 */
.byte 0x4b /* Left */
.asciz "[D" /* Left/xterm */
.byte 0x47 /* Home */
.asciz "[1~" /* Home/screen/vt102 */
.byte 0x47 /* Home */
.asciz "[H" /* Home/xterm */
.byte 0x4f /* End */
.asciz "[4~" /* End/screen/vt102 */
.byte 0x4f /* End */
.asciz "[F" /* End/xterm */
.byte 0x48 /* Up */
.asciz "OA" /* Up/screen/vt102 app */
.byte 0x48 /* Up */
.asciz "[A" /* Up/xterm/vt102 ansi */
.byte 0x50 /* Down */
.asciz "OB" /* Down/screen/vt102 app */
.byte 0x50 /* Down */
.asciz "[B" /* Down/xterm/vt102 ansi */
.byte 0x49 /* PageUp */
.asciz "[5~" /* PageUp/screen/vt102/xterm */
.byte 0x51 /* PageDown */
.asciz "[6~" /* PageDown/screen/vt102/xterm */
.byte 0x4d /* Right */
.asciz "OC" /* Right/screen/vt102 app */
.byte 0x4d /* Right */
.asciz "[C" /* Right/xterm/vt102 ansi */
.byte 0 /* end of table marker */
/* init_serial_port
*
* Initialize serial port to 115200,8n1
* Serial interrupts disabled
*
* All registers except flags preserved
*/
init_serial_port:
pushw %ax
pushw %dx
pushw %bx
movw %cs:serial_port_base_address, %dx
addw $IER_OFFSET, %dx
xorb %al, %al
outb %al, %dx /* disable all serial interrupts */
addw $(LCR_OFFSET - IER_OFFSET), %dx /* LCR */
movb $(LCR_VALUE|LCR_DLAB), %al
outb %al, %dx /* enable divisor access */
movw %cs:serial_port_base_address, %dx
movw $(PORT_DIVISOR/PORT_SPEED), %bx
movb %bl, %al /* al = lsb of divisor */
outb %al, %dx /* set divisor latch lsb */
movb %bh, %al /* al = msb of divisor */
incw %dx
outb %al, %dx /* set divisor latch msb */
movw %cs:serial_port_base_address, %dx
addw $LCR_OFFSET, %dx
movb $LCR_VALUE, %al
outb %al, %dx /* disable divisor access */
addw $(MCR_OFFSET - LCR_OFFSET), %dx /* MCR */
movb $MCR_DTRRTS, %al
outb %al, %dx /* enable DTR + RTS */
movw %cs:serial_port_base_address, %dx
addw $FCR_OFFSET, %dx
movb $FCR_FIFO_ENABLE, %al
outb %al, %dx /* enable FIFOs */
popw %bx
popw %dx
popw %ax
ret
/* get_serial_lsr
*
* return serial line status register in %al
* return offset to serial port line status register io port in %dx
* all other registers except flags unchanged
*
* if status == 0xff return ZF=1, else return ZF=0
*/
get_serial_lsr:
movw %cs:serial_port_base_address, %dx
addw $LSR_OFFSET, %dx
inb %dx, %al
cmpb $0xff, %al
ret
/*
* get_byte
*
* get serial byte in %al, scancode in %ah [FIXME: EFI console input]
*
* all registers except %ax preserved
*
*/
get_byte:
pushw %dx
pushw %bx
next_serial_char:
call get_serial_lsr /* get serial lsr in %al */
jz get_byte_tail /* no port present... */
testb $1, %al /* bit 0 of LSR = 1 = data available */
jz get_byte_tail /* no input waiting */
/* new character found on serial port */
/* convert it to a scancode */
movw %cs:serial_port_base_address, %dx
inb %dx, %al /* al = serial input char */
testb $0x80, %al /* non-ascii char received? */
jnz next_serial_char /* throw char away */
movb %al, %dl /* dl = character read */
pushw %ds
pushw %cs
popw %ds /* ds = cs */
movw $ascii2scan, %bx /* table to translate ascii->scan */
xlatb /* translate char to scancode */
popw %ds
/* shift status is ignored at this point, may be used later */
andb $0x7f, %al /* strip shift status from table */
movb %al, %ah /* scancode goes in high byte */
movb %dl, %al /* "translated" ascii in lower byte */
cmpb $0x7f, %al /* Did the user transmit ascii DEL? */
jnz get_byte_not_del /* if not, don't do anything to al */
movb $0x08, %al /* else delete becomes backspace */
get_byte_not_del:
testw %ax, %ax /* clear zero flag */
get_byte_tail:
popw %bx
popw %dx
ret
/*
* poll_byte
*
* get serial byte in %al, scancode in %ah [FIXME: EFI console input]
* retry up to 65536 times for an expected input byte
*
* all registers except %ax preserved
*
*/
poll_byte:
pushw %cx
xorw %cx, %cx
poll_byte_retry:
inb $0xed, %al
call get_byte
loopz poll_byte_retry /* repeat while zf set or cx != 0 */
popw %cx
ret
/*
* get_multibyte
*
* after an escape character, poll for terminal keys that generate
* an escape code plus multiple bytes (up to four).
*
* if no byte is waiting, all registers preserved except flags
* if more bytes are waiting, all registers preserved except %ax and flags
*
*/
get_multibyte:
pushw %bp /* bp points to temp buffer on stack */
pushw %bx /* bx points to multibyteinput table */
pushw %cx /* cx will count chars */
pushw %ax /* ax will receive chars */
pushl $0 /* make space on stack for 4 chars */
xorw %cx, %cx /* cx = 0 */
movw %sp, %bp /* point bp at temp data */
call poll_byte /* is a character waiting? */
jz get_multibyte_tail /* if not, bail */
get_multibyte_store:
movb %al, (%bp) /* store char received */
incb %cl /* mark one char received */
incw %bp /* point to next char */
cmpb $4, %cl /* got enough chars? */
jz got_multibyte /* no strings longer than 4 chars */
call poll_byte /* is another char waiting? */
jnz get_multibyte_store /* store a new one if it's there */
got_multibyte:
movw $multibyteinput, %bx /* point to first scancode */
got_multibyte_findkey:
movw %sp, %bp /* bp = start of buffer */
movb %cs:(%bx), %ah /* ah = scancode */
incw %bx /* bx = start of test string */
orb %ah, %ah /* is it zero? */
jz get_multibyte_tail /* if so, bail, key not found */
got_multibyte_nextchar:
movb %cs:(%bx), %ch /* ch = test char to compare */
incw %bx /* point to next char */
orb %ch, %ch /* is char to compare NUL? */
jz got_multibyte_key /* matched to end of a string! */
cmpb %ch, (%bp) /* input tmp buf equal to test char? */
jnz got_multibyte_try_next_key
/* note: expected that test string will be nul before input string */
/* no attempt is made to ensure no more than 4 bytes stack read */
incw %bp /* point to next input */
jmp got_multibyte_nextchar
got_multibyte_try_next_key: /* align to next scancode/ascii pair */
movb %cs:(%bx), %ch /* ch = test char to compare */
incw %bx /* point to next char */
orb %ch, %ch /* is char to compare NUL? */
jnz got_multibyte_try_next_key
jmp got_multibyte_findkey
got_multibyte_key:
xorb %al, %al /* ascii value = 0 for special keys */
movw %sp, %bp
movw %ax, 4(%bp) /* overwrite old %ax value with key */
get_multibyte_tail:
addw $4, %sp /* pop temp space */
popw %ax
popw %cx
popw %bx
popw %bp
ret
/*
* send_byte
*
* send character in %al to serial port [FIXME: EFI console out]
*
* all registers preserved except flags
*
*/
send_byte:
pushw %ax
pushw %dx
pushw %cx
testb $0x80, %al /* don't send non-ascii chars */
jnz send_tail /* these should be translated earlier */
movb %al, %ah /* save char to output in %ah */
movw $0xFFF0, %cx /* only retry 65520 times */
serial_ready_test:
call get_serial_lsr /* get serial lsr in %al */
testb $TRANSMIT_READY_BIT, %al
loopz serial_ready_test /* if !tx ready, loop while cx!=0 */
movb %ah, %al
movw %cs:serial_port_base_address, %dx
outb %al, %dx
send_tail:
popw %cx
popw %dx
popw %ax
ret
/*
* translate_char
*
* translate vga character in %al to ascii
*
* returns:
* al = translated character
*
* all registers except %al preserved
*
*/
translate_char:
pushw %bx
pushw %ds
pushw %cs
popw %ds /* ds = cs */
testb $0x80, %al
jz translate_char_ctrl
andb $0x7f, %al
movw $high2ascii, %bx
xlatb
translate_char_ctrl:
cmpb $0x20, %al
jnc translate_char_tail
movw $ctrl2ascii, %bx
xlatb
translate_char_tail:
popw %ds
popw %bx
ret
/*
* translate_char_tty
*
* translate vga character in %al to ascii
* unless %al == 7, 8, 10, or 13 (bell, bs, lf, cr)
*
* returns:
* al = translated character
*
* all registers except %al preserved
*
*/
translate_char_tty:
cmpb $0x07, %al /* bell */
jz translate_char_tty_tail
cmpb $0x08, %al /* backspace */
jz translate_char_tty_tail
cmpb $0x0a, %al /* LF */
jz translate_char_tty_tail
cmpb $0x0d, %al /* CR */
jz translate_char_tty_tail
call translate_char
translate_char_tty_tail:
ret
/*
* send_char
*
* send character 0 - 255 in %al out through serial port
* increment cursor position without control processing
*
* send_byte is used for data that isn't tracked
*
* send_char is used for text that should be tracked
* send_char outputs all characters as non-control chars
*
* returns:
* al = translated character
*
* all registers except %al preserved
*
*/
send_char:
call sgabioslog_save_char /* save original char+pos */
call translate_char
jmp send_char_tty_out
/* after ctrl translation, same as send_char_tty */
/*
* send_char_tty
*
* send character 0 - 255 in %al out through serial port
* increment cursor position *with* control processing
* for bell, linefeed, cr, and backspace (others all printable)
*
* send_byte is used for data that isn't tracked
*
* send_char_tty is used for text that should be tracked
*
* returns:
* al = translated character
*
* all registers except %al preserved
*
*/
/* send character 0 - 255 in %al out through serial port */
/* increment cursor position with CR/LF/Backspace processing */
send_char_tty:
call sgabioslog_save_char /* save original char+pos */
call translate_char_tty
send_char_tty_out:
pushw %dx
call update_serial_cursor
call get_current_cursor /* vga cursor in %dx */
cmpb $0x0d, %al /* CR */
jnz send_char_tty_nul /* if not CR, check for NUL */
orb %dl, %dl /* already at col 0? */
jz send_char_tty_tail /* no need to re-send CR */
send_char_tty_nul:
orb %al, %al /* %al == 0 ? (nul) */
/* more than likely, we have NUL at this point because the caller */
/* tried to read a char using int $0x10, %ah=8, and is trying */
/* to re-output it with different attributes - for now send nothing */
jz send_char_tty_tail
send_char_tty_write:
call memconsole_log_char /* log character sent */
call send_byte
cmpb $0x07, %al /* bell */
jz send_char_tty_tail /* no cursor update for bell */
cmpb $0x08, %al /* backspace */
jz send_char_tty_backspace
cmpb $0x0a, %al /* LF */
jz send_char_tty_lf
cmpb $0x0d, %al /* CR */
jz send_char_tty_cr
incb %dl
jmp send_char_tty_tail
send_char_tty_backspace:
orb %dl, %dl
jz send_char_tty_tail
decb %dl
jmp send_char_tty_tail
send_char_tty_lf:
incb %dh
jmp send_char_tty_tail
send_char_tty_cr:
xorb %dl, %dl
send_char_tty_tail:
cmpb %cs:term_cols, %dl
jc send_char_tty_check_rows
movb %cs:term_cols, %dl
decb %dl /* dl = cols - 1 */
send_char_tty_check_rows:
cmpb %cs:term_rows, %dh
jc send_char_tty_save_cursor
movb %cs:term_rows, %dh
decb %dh /* dh = rows - 1 */
send_char_tty_save_cursor:
call set_current_cursor
pushw %ds
pushw $BDA_SEG
popw %ds
/* save current position as the serial terminal position */
/* since a character was just output at that position */
movw %dx, BDA_SERIAL_POS
popw %ds
popw %dx
ret
/*
* send_asciz_out
*
* send nul terminated string pointed to by %ds:%si
* to serial port without text tracking
*
* indended to be used for multi-byte send_byte
*
* all registers preserved except flags
*/
send_asciz_out:
pushw %ax
pushw %si
cld
send_asciz_loop:
lodsb
test %al,%al
jz send_asciz_end
call send_byte
jmp send_asciz_loop
send_asciz_end:
popw %si
popw %ax
ret
/*
* send_string
*
* send cx chars in string pointed to by %ds:%si
* to serial port with tty tracking
*
* indended to be used for multi-byte send_char_tty
*
* all registers preserved except flags
*/
send_string:
pushw %ax
pushw %si
cld
send_string_loop:
lodsb
call send_char_tty
loop send_string_loop
popw %si
popw %ax
ret
/*
* send_string
*
* send cx chars in string pointed to by %ds:%si
* with interleaved attribute data
*
* indended to be used for multi-byte send_char_tty
* with interleaved vga attribute updates
*
* all registers preserved except flags
*/
send_attr_string:
pushw %ax
pushw %bx
pushw %si
cld
send_attr_string_loop:
lodsb
call send_char_tty
lodsb
movb %al, %bl
call send_attribute /* send attribute in %bl */
loop send_attr_string_loop
popw %si
popw %bx
popw %ax
ret
/*
* send_number
*
* send ascii version of number in %al to serial port
*
* intended for ansi cursor positions and attributes,
* so cursor position is not tracked/updated
*
* all registers preserved except flags
*/
send_number:
pushw %ax
pushw %bx
aam /* ah = al/10, al = al mod 10 */
movw %ax, %bx /* bh = al/10, bl = al mod 10 */
movb %bh, %al
aam /* ah = bh/10, al = bh mod 10 */
movb %al, %bh /* bh = 10s digit, bl = 1s digit */
movb %ah, %al /* ah = al = 100s digit */
testb %al, %al /* is there a 100s digit? */
jz send_tens /* move to tens if not */
orb $0x30, %al /* al = ascii value of digit */
call send_byte
send_tens:
orb %bh, %ah /* bh = 10s, ah = 100s digits */
jz send_ones /* non-zero = must send tens */
movb %bh, %al /* al = bh = 10s digit */
orb $0x30, %al /* al = ascii value of digit */
call send_byte
send_ones:
movb %bl, %al /* al = bl = 1s digit */
orb $0x30, %al /* al = ascii value of digit */
call send_byte
popw %bx
popw %ax
ret
/*
* send_crlf
*
* send CRLF to serial port
*
* FIXME: used at vga init and for scrolling terminal
* so position is not tracked. Callers of this routine
* predate the code that does smart tty/cursor output.
*
* Callers should probably be changed to use those
* routines or send_crlf changed to use them and
* terminal scrolling fixed to use linefeed only.
*
* all registers preserved except flags
*/
send_crlf:
pushw %ax
movb $0x0d, %al
call send_byte
movb $0x0a, %al
call send_byte
popw %ax
ret
/*
* send_ansi_csi
*
* send ESCAPE [ to serial port
*
* output is not tracked since these are control sequences
*
* all registers preserved except flags
*/
send_ansi_csi: /* transmit ESC [ */
pushw %ax
movb $0x1b, %al /* escape */
call send_byte
movb $0x5b, %al /* [ */
call send_byte
popw %ax
ret
/*
* send_ansi_csi_2num
*
* send ESC [ %dh ; %dl to serial port
*
* since both position and attribute updates generally have
* two parameters, this function converts values in dx to
* two ascii numbers. It's expected that the caller will
* output the final trailing H or m or whatever is required.
*
* output is not tracked since these are control sequences
*
* all registers preserved except flags
*/
send_ansi_csi_2num:
/* send ESC [ %dh ; %dl */
pushw %ax
call send_ansi_csi /* esc [ */
movb %dh, %al
call send_number
movb $0x3b, %al /* semicolon */
call send_byte
movb %dl, %al
call send_number
popw %ax
ret
/*
* send_ansi_cursor_pos
*
* send ESC [ %dh+1 ; %dl+1 to serial port to position
* cursor
*
* since both position and attribute updates generally have
* two parameters, this function converts values in dx to
* two ascii numbers, after adding 1 to both dh and dl.
*
* output is not tracked since this is a control sequence
*
* all registers preserved except flags
*/
send_ansi_cursor_pos:
pushw %ax
pushw %dx
addw $0x0101, %dx /* dh += 1, dl += 1 */
call send_ansi_csi_2num /* send esc [ %dh+1;%dl+1 */
movb $0x48, %al /* H */
call send_byte
popw %dx
popw %ax
ret
/*
* send_attribute
*
* send ansi attribute change ESC [ 4x ; 3y ; (1|22)m
* if the attribute has changed since last sent (stored in bda)
*
* output is not tracked since this is a control sequence
*
* all registers preserved except flags
*/
send_attribute:
andb $0x7f, %bl /* ansi has no bright bg */
pushw %ds
pushw %es
pushw %ax
pushw %bx
pushw %dx
pushw $BDA_SEG
popw %es /* es = 0x40 */
pushw %cs
popw %ds /* ds = cs */
cmpb %es:BDA_COLOR_VAL, %bl
jz send_attribute_tail
cmpb $0x07, %bl /* is it white on black? */
jnz send_attribute_color
/* for white on black, send esc [ m */
call send_ansi_csi
jmp send_attribute_m /* send the m, return */
send_attribute_color:
movb %bl, %ah /* ah = attribute */
movw $colortable, %bx
movb %ah, %al
andb $7, %al /* al = fg attr */
xlatb /* al = fg ansi num */
movb %al, %dl /* dl = fg ansi num */
movb %ah, %al
shrb $4, %al /* al = bg attr */
xlatb /* al = bg ansi num */
movb %al, %dh /* dh = bg ansi num */
addw $0x281e, %dx /* 3x=setfg, 4x=setbg */
call send_ansi_csi_2num
movb $0x3b, %al /* semicolon */
call send_byte
shlb $4, %ah /* bright text? */
sets %al /* if bit 7, al = 1 */
js send_attribute_intensity
movb $22, %al /* 22 = normal intensity */
send_attribute_intensity:
call send_number /* either 22 or 1 */
send_attribute_m:
movb $0x6d, %al /* m */
call send_byte
send_attribute_tail:
popw %dx
popw %bx
/* mark attribute in %bl the current one */
movb %bl, %es:BDA_COLOR_VAL
popw %ax
popw %es
popw %ds
ret
/*
* serial_get_input
*
* common code for both interrupt-driven and non-interrupt
* driven serial input. Called only when LSR bit 1 is set.
*
* No parameters, no return values
*
* Preserves all registers
*/
serial_get_input:
pushf
/* be paranoid about int 9h happening during update */
cli
pushaw
pushw %ds
/* next char input buffer is at 0x40:0x1c */
pushw $BDA_SEG
popw %ds /* es = 0x40 */
call get_byte /* next scancode/byte in %ax */
cmpb $0x1b, %al /* look for escape */
jnz serial_gotkey /* not escape, don't look for more bytes */
call get_multibyte /* look for any chars after escape */
serial_gotkey:
movw KBD_TAIL, %bx /* bx = keyboard tail pointer */
movw %ax, (%bx) /* store key in buffer */
addw $2, %bx /* point to next location */
cmpw $KBD_BUF_END, %bx /* did the buffer wrap? */
jb kbd_buf_no_wrap
movw $KBD_BUF_START, %bx
kbd_buf_no_wrap:
movw %bx, KBD_TAIL /* update tail pointer to show key */
popw %ds
popaw
popf
ret
/*
* irq3_isr
*
* entry point for irq 3 / int 0x0b / exception 11
*
* Called when COM2 or COM4 have characters pending
*
* The segment not present exception should never happen
* in real mode 16-bit code like this, but just to be safe,
* if this interrupt is invoked and no characters are
* pending on the port found in serial_port_base_address,
* this routine will chain to the original handler.
*
* If characters are found pending, they will be processed
* and control returned via iret.
*/
irq3_isr:
#if 0
pushw %ax
pushw %dx
/* placeholder, this shouldn't ever happen */
/* no interrupts are configured outside COM1 */
call get_serial_lsr /* get serial lsr in %al */
jz chain_irq3 /* no port present... */
testb $1, %al /* bit 0 of LSR = 1 = data available */
jz chain_irq3 /* no input waiting */
call serial_get_input /* get input and stuff kbd buffer */
movb $0x20, %al
outb %al, $0x20 /* send non-specific EOI */
popw %dx
popw %ax
iret
chain_irq3:
popw %dx
popw %ax
#endif
jmp do_old_irq3
/*
* irq4_isr
*
* entry point for irq 4 / int 0x0c / exception 12
*
* Called when COM1 or COM3 have characters pending
*
* The stack fault exception may occur if code attempts to
* read from sp:0xffff, so if this interrupt is invoked and
* no characters are pending on the port found in
* serial_port_base_address, this routine will chain to the
* original handler.
*
* If characters are found pending, they will be processed
* and control returned via iret.
*/
irq4_isr:
#if 0
pushw %ax
pushw %dx
call get_serial_lsr /* get serial lsr in %al */
jz chain_irq4 /* no port present... */
testb $1, %al /* bit 0 of LSR = 1 = data available */
jz chain_irq4 /* no input waiting */
call serial_get_input /* get input and stuff kbd buffer */
movb $0x20, %al
outb %al, $0x20 /* send non-specific EOI */
popw %dx
popw %ax
iret
chain_irq4:
popw %dx
popw %ax
#endif
jmp do_old_irq4
/*
* int14h_isr
*
* entry point for int 14h
*
*/
int14h_isr:
pushaw
movw %sp, %bp
addw $16, %bp /* bp points to return address */
orb %ah, %ah /* fn 0x00, initialize port */
jz int14h_init_port
cmpb $0x04, %ah /* fn 0x04, extended intialize */
jnz chain_isr14h
int14h_init_port:
/* check for init port = current port */
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movw %dx, %bx /* bx = port number */
shlw $1, %bx /* bx = port number * 2 */
andw $7, %bx /* bx = bda offset of serial io addr */
movw (%bx), %cx /* cx = io address of port to init */
popw %ds /* restore original ds */
cmpw %cx, %cs:serial_port_base_address
jnz chain_isr14h /* if different, don't get in the way */
/* init port == current port */
pushw %ds
/* LILO 22.6 HACK STARTS HERE */
movw (%bp), %bx /* return address for int 14h call */
movw 2(%bp), %ds /* return segment for int 14h call */
cmpl $0x4f4c494c, 0x06 /* does segment have lilo signature? */
jnz int14h_init_tail /* not lilo, bail on hack */
cmpw $0x0616, 0x0a /* does version match lilo 22.6? */
jnz int14h_init_tail /* unknown lilo release, bail on hack */
movb $0, 0x12 /* set lilo com port = 0 */
movl $0x90c3585a, (%bx) /* return code= pop dx;pop ax;ret;nop */
/* now lilo 22.6's own serial out is permanently disabled */
/* this prevents double-character output from int10h + serial */
/* this also prevents lilo from stealing serial input chars */
/* END LILO 22.6 HACK */
int14h_init_tail:
popw %ds
popaw
pushw %dx /* get_serial_lsr trashes %dx */
call get_serial_lsr /* return serial status in %al */
xorb %ah, %ah /* return serial status in %ax */
popw %dx /* restore %dx */
iret
chain_isr14h:
popaw
jmp do_old_int14h
/*
* int16h_isr
*
* entry point for int 16h
*
* keyboard characters are usually retrieved by calling
* int 16h, generally placed in the keyboard buffer by
* irq 1 (int 9h). Poll serial port for new data before
* chaining to int 16h to fake irq 1 behavior
*
* all registers preserved except flags (later iret will restore)
* bda updated with a new keypress if available
*
* FIXME: handle multi-byte keypresses like cursor up/down
* to send proper scancodes for navigating lilo menus
*/
int16h_isr:
pushw %ax
pushw %dx
/* each time int 16h is invoked, fake an int 9h */
/* except read the serial input buffer */
/* then chain to the original int 16h for processing */
call get_serial_lsr
jz chain_isr16h /* no port present... */
testb $1, %al /* bit 0 of LSR = 1 = data available */
jz chain_isr16h /* no input waiting */
call serial_get_input /* get input and stuff kbd buffer */
/* for now, leave remaining chars pending in serial fifo */
/* int 16h callers only get one char at a time anyway */
chain_isr16h:
popw %dx
popw %ax
jmp do_old_int16h
/*
* update serial_cursor
*
* figure out where the cursor was, and where it's going
* use the minimal amount of serial output to get it there
* input: vga cursor and serial cursor positions stored in BDA
*
* all registers preserved except flags
* bda updated with new position for serial console cursor
*/
update_serial_cursor:
pushw %ax
pushw %bx
pushw %dx
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
call get_current_cursor /* dh = row, dl = col */
movw BDA_SERIAL_POS, %bx /* bh = row, bl = col */
subb %dl, %bl /* -col update */
negb %bl /* col update */
subb %dh, %bh /* -row update */
negb %bh /* row update */
/* handle a few special movement cases */
/* cr, lf, bs, bs+bs, space, else send full ansi position */
orb %dl, %dl /* column zero? */
jnz update_serial_cursor_lf
movb $0x0d, %al /* CR */
call send_byte
xorb %bl, %bl /* mark no diff in col */
update_serial_cursor_lf:
cmpb $1, %bh /* +1 row? */
jnz update_serial_cursor_bs
movb $0x0a, %al /* LF */
call send_byte
xorb %bh, %bh /* mark no diff in row */
update_serial_cursor_bs:
cmpb $-1, %bl /* one char back */
jz update_serial_cursor_one_bs
cmpb $-2, %bl /* two chars back */
jnz update_serial_cursor_space /* check for space */
movb $0x08, %al /* BS */
call send_byte
update_serial_cursor_one_bs:
movb $0x08, %al /* BS */
call send_byte
xorb %bl, %bl /* mark no diff in col */
update_serial_cursor_space:
cmpb $1, %bl /* one char forward */
jnz update_serial_cursor_up
movb $0x20, %al /* space */
call send_byte
xorb %bl, %bl /* mark no diff in col */
update_serial_cursor_up:
cmpb $-1, %bh /* -1 row? */
jnz update_serial_cursor_full /* do full ansi pos update */
call send_ansi_csi /* send ESC [ A (cursor up) */
movb $0x41, %al /* A */
call send_byte
xorb %bh, %bh /* mark no diff in row */
update_serial_cursor_full:
orw %bx, %bx /* diff = 0? */
jz update_serial_cursor_done
call send_ansi_cursor_pos /* set cursor pos from dh,dl */
update_serial_cursor_done:
movw %dx, BDA_SERIAL_POS
popw %ds
popw %dx
popw %bx
popw %ax
ret
/*
* write_teletype
*
* handle int 10h, function 0eh
*
* ah = 0x0e write teletype character
* al = character ascii code
* bh = display page number
*
* all registers except %al preserved
* caller will restore all registers
*/
write_teletype:
pushw %bx
movb $0x07, %bl /* black bg, white fg */
call send_attribute
popw %bx
call send_char_tty
ret
/*
* write_attr_char
*
* handle int 10h, function 09h
*
* ah = 0x09 write attribute/character at current cursor position
* al = character ascii code
* bh = display page number
* bl = character attribute
* cx = repetition count
*
* does not update cursor position
* all registers except %cx and %al preserved
* caller will restore all registers
*/
write_attr_char:
call send_attribute /* send attribute in %bl */
jmp write_char_common
/*
* write_char
*
* handle int 10h, function 0ah
*
* ah = 0x0a write character at current cursor position
* al = character ascii code
* bh = display page number
* cx = repetition count
*
* does not update cursor position
* all registers except %cx and %al preserved
* caller will restore all registers
*/
write_char:
pushw %bx
movb $0x07, %bl /* black bg, white fg */
call send_attribute
popw %bx
write_char_common:
call get_current_cursor
call send_char
/* make cx=0 and cx=1 only output one char */
cmpw $1, %cx
jbe write_char_tail
decw %cx
jmp write_char
write_char_tail:
/* put cursor back where it was on entry */
call set_current_cursor
ret
/*
* write_string
*
* handle int 10h, function 13h
*
* ah = 0x13 write character at current cursor position
* al = 0, data = char, ..., no cursor update
* al = 1, data = char, ..., cursor at end of string
* al = 2, data = char+attr, ..., no cursor update
* al = 3, data = char+attr, ..., cursor at end of string
* bh = display page number
* bl = character attribute for all chars (if al = 0 or 1)
* cx = characters in string (attributes don't count)
* dh = cursor row start
* dl = cursor column start
* es:bp = pointer to source text string in memory
*
* all registers preserved except flags
* caller will restore all registers
*/
write_string:
call set_cursor_position
pushw %ds
pushw %es
pushw %es
popw %ds /* ds = es */
movw %bp, %si /* si = bp */
testb $2, %al
jnz write_attr_string
call send_attribute /* send attribute in %bl */
test %cx, %cx
jz write_string_empty
call send_string /* plaintext out */
write_string_empty:
jmp write_string_update_cursor
write_attr_string:
call send_attr_string /* text+attrib out */
write_string_update_cursor:
testb $1, %al /* cursor update? */
jnz write_string_tail /* yes? already happened */
/* restore entry cursor position if no update */
call set_cursor_position
write_string_tail:
popw %es
popw %ds
ret
/*
* set_cursor_position
*
* handle int 10h, function 02h
*
* ah = 0x02 set cursor position
* bh = display page number
* dh = cursor row
* dl = cursor column
*
* update bda cursor position with value in %dx
* serial console cursor only updated on text output
* this routine also called by set_current_cursor
* which won't bother setting ah = 2
*
* all registers preserved except flags
*/
set_cursor_position:
pushw %ax
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movzbw %bh, %ax /* ax = page number */
andb $0x07, %al /* prevent invalid page number */
shlb $1, %al /* calculate word offset */
addb $BDA_CURSOR_BUF, %al /* ax = cursor save offset */
movw %ax, %bx /* bx = cursor save offset */
movw %dx, (%bx) /* save new cursor value */
popw %ds
popw %ax
ret
/*
* set_current_cursor
*
* get current display page number and call set_cursor_positon
* to store the row/column value in dx to the bda
*
* all registers preserved except flags
*/
set_current_cursor:
pushw %ds
pushw %bx
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb BDA_ACTIVE_PAGE, %bh
call set_cursor_position
popw %bx
popw %ds
ret
/*
* get_cursor_common
*
* read cursor position for page %bh from bda into %dx
*
* returns:
* dh = cursor row
* dl = cursor column
* ch = cursor start scanline
* cl = cursor end scanline
*
* all registers except %dx, %cx preserved
*/
get_cursor_common:
pushw %bx
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movzbw %bh, %bx /* dx = current page */
andb $7, %bl
shlb $1, %bl
addb $BDA_CURSOR_BUF, %bl
movw (%bx), %dx /* get cursor pos */
movw BDA_CURSOR_SCAN, %cx
popw %ds
popw %bx
ret
/*
* get_current_cursor
*
* read cursor position for current page from bda into %dx
*
* returns:
* dh = cursor row
* dl = cursor column
*
* all registers except %dx preserved
*/
get_current_cursor:
pushw %ds
pushw %bx
pushw %cx
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb BDA_ACTIVE_PAGE, %bh
call get_cursor_common
popw %cx
popw %bx
popw %ds
ret
/*
* get_cursor_position
*
* handle int 10h, function 03h
*
* ah = 0x02 get cursor position
* bh = display page number
*
* returns:
* ax = 0
* ch = cursor start scanline
* ch = cursor end scanline
* dh = cursor row
* dl = cursor column
*
* all registers except %ax, %cx, %dx preserved
*/
get_cursor_position:
call bail_if_vga_attached /* does not return if vga attached */
popw %ax /* not chaining, pop fake return address */
popw %dx /* not chaining, pop saved cursor position */
popaw /* not chaining to old int 10h, pop saved state */
call get_cursor_common
xorw %ax, %ax
iret
/*
* return_current_video_state
*
* handle int 10h, function 0fh
*
* ah = 0x0f return current video state
*
* returns:
* ah = number of columns on screen (from 40:4a)
* al = current video mode setting (from 40:49)
* bh = active display page number (from 40:62)
*
* all registers except %ax and %bh preserved
*/
read_current_video_state:
call bail_if_vga_attached /* does not return if vga attached */
popw %ax /* not chaining, pop fake return address */
popw %dx /* not chaining, pop saved cursor position */
popaw /* not chaining to old int 10h, pop saved state */
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb BDA_COLS, %ah
movb BDA_MODE_NUM, %al
movb BDA_ACTIVE_PAGE, %bh
popw %ds
iret
/*
* read_attr_char
*
* handle int 10h, function 08h
*
* ah = 0x08 read character/attribute from screen
*
* returns:
* ah = attribute at current cursor position
* al = character read from current cursor position
*
* all registers preserved except %ax and flags
*/
read_attr_char:
call bail_if_vga_attached /* does not return if vga attached */
popw %ax /* not chaining, pop fake return address */
popw %dx /* not chaining, pop saved cursor position */
popaw /* not chaining to old int 10h, pop saved state */
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb BDA_COLOR_VAL, %ah /* return last color value */
call sgabioslog_get_char
popw %ds
iret
/*
* set_video_mode
*
* handle int 10h, function 00h
*
* ah = 0x00 set video mode
* al = video mode
*
* unless bit 7 of al = 1, setting mode clears screen
*
* all registers preserved except %bh, %dx, flags
*/
set_video_mode:
testb $0x80, %al /* preserve screen flag? */
jnz set_video_mode_tail
call send_ansi_csi
movb $0x32, %al /* 2 */
call send_byte
movb $0x4a, %al /* J */
call send_byte
set_video_mode_tail:
movb $0x07, %bl /* white on black text */
call send_attribute /* send attribute in %bl */
/* set cursor position to 0,0 */
xorb %bh, %bh /* page 0 */
xorw %dx, %dx
jmp set_cursor_position
/*
* scroll_page_up
*
* handle int 10h, function 06h
*
* ah = 0x06 scroll current page up
* al = scroll distance in character rows (0 blanks entire area)
* bh = attribute to used on blanked lines
* ch = top row (upper left corner) of window
* cl = left-most column (upper left corner) of window
* dh = bottom row (lower right corner) of window
* dl = right-most column (lower right corner) of window
*
* all registers preserved except flags
*/
scroll_page_up:
pushw %si
pushw %dx
call get_current_cursor /* save current cursor */
movw %dx, %si /* si = vga cursor pos */
popw %dx
cmpb $0, %al /* al = 0 = clear window */
jz scroll_common_clear
pushw %ax
call send_ansi_csi /* CSI [ %al S */
call send_number
movb $0x53, %al /* S */
call send_byte
popw %dx
popw %si
ret
/*
* scroll_common_clear
*
* common tail for up/down scrolls to clear window specified
* in %cx and %dx.
*
* stack should contain saved copy of si
* si = original vga cursor position on service entry
*
* bh = attribute to used on blanked lines
* ch = top row (upper left corner) of window
* cl = left-most column (upper left corner) of window
* dh = bottom row (lower right corner) of window
* dl = right-most column (lower right corner) of window
*/
scroll_common_clear:
pushw %ax
xchgb %bl, %bh /* bl = attribute, bh = old bl */
call send_attribute /* send attribute in %bl */
xchgb %bl, %bh /* restore bx */
pushw %ds
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
/* check to see if region is full screen, and attribute default */
orw %cx, %cx /* is top left 0,0? */
jnz scroll_common_window /* no, handle window */
cmpb $0x07, %bh /* is attribute white on black? */
jnz scroll_common_window /* no, must write spaces */
#ifdef LILO_CLEAR_WORKAROUND_NOT_REQUIRED
cmpb %cs:term_cols, %dl /* is right less than cols ? */
jc scroll_common_window /* if so, handle window */
cmpb %cs:term_rows, %dh /* is bottom less than rows ? */
jc scroll_common_window /* if so, handle window */
#endif
/* safe to send standard clear screen sequence */
call send_ansi_csi /* send ESC [ */
movb $0x32, %al /* 2 */
call send_byte
movb $0x4a, %al /* J */
call send_byte
jmp scroll_common_tail
scroll_common_window:
pushw %dx
movw %cx, %dx /* dx = upper right */
call set_current_cursor
popw %dx
pushw %cx
/* setup cx with count of chars to clear per row */
xorb %ch, %ch
negb %cl
addb %dl, %cl /* cl = dl - cl */
incb %cl /* start = end col = clear 1 col */
cmpb %cs:term_cols, %cl /* is count < cols? */
jc scroll_common_row_ok /* if so then skip limit */
movb %cs:term_cols, %cl /* limit count to cols */
scroll_common_row_ok:
jz scroll_common_row_done /* count == 0 ? */
movb $0x20, %al /* space */
scroll_common_space_loop:
call send_char
loop scroll_common_space_loop /* send cx spaces */
scroll_common_row_done:
popw %cx
incb %ch /* top left now next row */
cmpb %dh, %ch
jbe scroll_common_window /* do next row */
scroll_common_tail:
popw %ds
popw %ax
pushw %dx
movw %si, %dx /* dx = saved vga cursor pos */
call set_current_cursor /* restore saved cursor */
popw %dx
popw %si
ret
/*
* scroll_page_down
*
* handle int 10h, function 07h
*
* ah = 0x07 scroll current page down
* al = scroll distance in character rows (0 blanks entire area)
* bh = attribute to used on blanked lines
* ch = top row (upper left corner) of window
* cl = left-most column (upper left corner) of window
* dh = bottom row (lower right corner) of window
* dl = right-most column (lower right corner) of window
*
* FIXME: this routine doesn't handle windowing, it currently
* only handles one line screen scrolls and erasing entire screen
*
* all registers preserved except flags
*/
scroll_page_down:
pushw %si
pushw %dx
call get_current_cursor /* save current cursor */
movw %dx, %si /* si = vga cursor pos */
popw %dx
cmpb $0, %al /* al = 0 = clear window */
jz scroll_common_clear
pushw %ax
call send_ansi_csi /* CSI [ %al T */
call send_number
movb $0x54, %al /* T */
call send_byte
popw %dx
popw %si
ret
/*
* bail_if_vga_attached
*
* Check for vga installed, if not, return to caller.
* If so, pop return address, return to chain_isr_10h
*
* expected that routine calling this one has chain_isr_10h
* as the next item on the stack
*
* all registers except flags and sp preserved
*/
bail_if_vga_attached:
cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */
jnz bail_tail /* if not, don't modify stack */
addw $2, %sp /* else drop first return address */
bail_tail:
ret /* return to caller or chain_isr_10h */
/*
* int10h_isr
*
* entry point for int 10h
*
* save all registers, force return to chain to previous int10h isr
* decide which function in ah needs to be dispatched
*
* ah = 0x00 set mode
* ah = 0x01 set cursor type
* ah = 0x02 set cursor position
* ah = 0x03 read cursor position
* ah = 0x04 read light pen position
* ah = 0x05 set active display page
* ah = 0x06 scroll active page up
* ah = 0x07 scroll active page down
* ah = 0x08 read attribute/character at cursor
* ah = 0x09 write attribute/character at cursor
* ah = 0x0a write character at cursor position
* ah = 0x0b set color palette
* ah = 0x0c write pixel
* ah = 0x0d read pixel
* ah = 0x0e write teletype
* ah = 0x0f read current video state
* ah = 0x10 set individual palette registers
* ah = 0x11 character generation (font control/info)
* ah = 0x12 alternate select (video control/info)
* ah = 0x13 write string
* ah = 0x1a read/write display combination code
* ah = 0x1b return functionality/state information
* ah = 0x1c save/restore video state
* ah = 0x4f vesa bios calls
* all registers preserved except flags (later iret will restore)
*/
int10h_isr:
pushaw
call get_current_cursor
pushw %dx /* save current cursor */
pushw %bp /* need bp for indexing off stack */
movw %sp, %bp /* bp = sp */
movw 14(%bp), %dx /* restore dx from earlier pushaw */
popw %bp /* restore old bp */
pushw $chain_isr10h /* force return to chain_isr10h */
testb %ah, %ah
jnz int10h_02
jmp set_video_mode
int10h_02:
cmpb $0x02, %ah
jnz int10h_03
jmp set_cursor_position
int10h_03:
cmpb $0x03, %ah
jnz int10h_06
jmp get_cursor_position
int10h_06:
cmpb $0x06, %ah
jnz int10h_07
jmp scroll_page_up
int10h_07:
cmpb $0x07, %ah
jnz int10h_08
jmp scroll_page_down
int10h_08:
cmpb $0x08, %ah
jnz int10h_09
jmp read_attr_char
int10h_09:
cmpb $0x09, %ah
jnz int10h_0a
jmp write_attr_char
int10h_0a:
cmpb $0x0a, %ah
jnz int10h_0e
jmp write_char
int10h_0e:
cmpb $0x0e, %ah
jnz int10h_0f
jmp write_teletype
int10h_0f:
cmpb $0x0f, %ah
jnz int10h_13
jmp read_current_video_state
int10h_13:
cmpb $0x13, %ah
jnz int10h_default
jmp write_string
int10h_default:
popw %ax /* pop chain_isr10h return address */
chain_isr10h:
popw %dx /* pop saved cursor */
cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */
jnz chain_post_cursor /* if not, don't restore the cursor */
call set_current_cursor /* restore cursor if vga attached */
chain_post_cursor:
popaw
jmp do_old_int10h
/*
* pnp_sga_init
*
* handle PnP initialization of option rom
*
* es:di = pointer to PnP structure
* ax = indication as to which vectors should be hooked
* by specifying th type of boot device this has
* been selected as
* bit 7..3= reserved(0)
* bit 2 = 1 = connect as IPL (int 13h)
* bit 1 = 1 = connect as primary video (int 10h)
* bit 0 = 1 = connect as primary input (int 9h)
* bx = card select number (probably 0xffff)
* dx = read data port address (probably 0xffff)
*
* return:
* ax = initialization status
* bit 8 = 1 = IPL device supports int 13h block dev format
* bit 7 = 1 = Output device supports int 10h char output
* bit 6 = 1 = Input device supports int 9h char input
* bit 5..4 = 00 = no IPL device attached
* 01 = unknown whether or not IPL device attached
* 10 = IPL device attached (RPL devices have connection)
* 11 = reserved
* bit 3..2 = 00 = no display device attached
* 01 = unknown whether or not display device attached
* 10 = display device attached
* 11 = reserved
* bit 1..0 = 00 = no input device attached
* 01 = unknown whether or not input device attached
* 10 = input device attached
* 11 = reserved
*
* all registers preserved except %ax
*/
pnp_sga_init:
/* FIXME: this is *wrong* -- init only what bios says to init */
movw $0xca, %ax /* 0xca = attached int 10h, 9h display, input */
/*
* sga_init
*
* legacy option rom entry point
*
* all registers preserved
*/
sga_init:
/* this is probably paranoid about register preservation */
pushfw
cli /* more paranoia */
pushaw
pushw %ds
pushw %es
pushw $0
popw %es /* es = 0 */
pushw %cs
popw %ds /* ds = cs */
/* get original ISR */
movl %es:0x28, %eax /* eax = old irq 3/int 0bh */
movl %eax, old_irq3 /* save away old irq 4/int 0bh */
movl %es:0x2c, %eax /* eax = old irq 4/int 0ch */
movl %eax, old_irq4 /* save away old irq 4/int 0ch */
movl %es:0x40, %eax /* eax = old int 10h */
movl %eax, old_int10h /* save away old int 10h */
movl %es:0x50, %eax /* eax = old int 14h */
movl %eax, old_int14h /* save away old int 14h */
movl %es:0x58, %eax /* eax = old int 16h */
movl %eax, old_int16h /* save away old int 16h */
movw $irq3_isr, %es:0x28 /* new irq 3 offset */
movw %cs, %es:0x2a /* write new irq 3 seg */
movw $irq4_isr, %es:0x2c /* new irq 4 offset */
movw %cs, %es:0x2e /* write new irq 4 seg */
movw $int10h_isr, %es:0x40 /* new int 10h offset */
movw %cs, %es:0x42 /* write new int10h seg */
movw $int14h_isr, %es:0x50 /* new int 14h offset */
movw %cs, %es:0x52 /* write new int14h seg */
movw $int16h_isr, %es:0x58 /* new int 16h offset */
movw %cs, %es:0x5a /* write new int16h seg */
/* empty input buffer to prepare for terminal sizing */
call init_serial_port
input_clear_loop:
call get_byte
jnz input_clear_loop
movw $term_init_string, %si
call send_asciz_out
push $BDA_SEG
push $BDA_SEG
popw %ds /* ds = 0x40 */
popw %es /* es = 0x40 */
movw $BDA_CURSOR_BUF, %di
input_timeout_loop:
/* get input from terminal until timeout found */
/* store input at 40:50 - 40:5e (cursor pos) */
call poll_byte
jz input_timeout
stosb /* es:di */
cmpw $0x5f, %di /* 14 characters max */
jnz input_timeout_loop /* good for more data */
input_timeout:
xorb %al, %al /* nul terminate input */
stosb
cmpw $0x58, %di /* less than 8 chars? */
jc resize_end /* too small to have valid data */
movw $BDA_CURSOR_BUF, %si /* point to start */
lodsw /* ax = first 2 chars */
cmpw $0x5b1b, %ax /* was it "ESC[" ? */
jnz resize_end /* reply starts ESC[row;colR */
xorb %bl, %bl /* bl = ascii->int conversion */
input_first_number:
lodsb /* al = next char */
cmpb $0x30, %al
jc resize_end /* char < 0x30 invalid */
cmpb $0x3a, %al /* is char < 0x3a */
jnc input_semicolon
andb $0x0f, %al /* al = 0 - 9 */
movb %bl, %ah /* ah = last conversion */
aad /* ax = (al + ah * 10) & 0xff */
movb %al, %bl /* bl = row ascii->int conversion */
jmp input_first_number
input_semicolon:
/* at this point bl should contain rows, al = ; */
/* sanity check, bail if invalid */
cmpb $0x3b, %al
jnz resize_end /* invalid input found */
cmpb $0x0a, %bl /* less than 10 rows? */
jc suspect_loopback /* consider input invalid */
xorb %bh, %bh /* bh = col ascii->int conversion */
input_second_number:
lodsb /* al = next char */
cmpb $0x30, %al
jc resize_end /* char < 0x30 invalid */
cmpb $0x3a, %al /* is char < 0x3a */
jnc input_final_r
andb $0x0f, %al /* al = 0 - 9 */
movb %bh, %ah /* ah = last conversion */
aad /* ax = (al + ah * 10) & 0xff */
movb %al, %bh /* bh = ascii->int conversion */
jmp input_second_number
input_final_r:
cmpb $0x52, %al /* is al = 'R' ? */
jnz suspect_loopback /* invalid input found */
movb %bl, %cs:term_rows /* save away bl rows value */
cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */
jz resize_end /* if so, leave term_cols at 80 */
movb %bh, %cs:term_cols /* save away bh cols value */
jmp resize_end
suspect_loopback:
/*
* characters were received that look like what we sent out
* at this point, assume that a loopback device was plugged in
* and disable any future serial port reads or writes, by pointing
* output to port 0x2e8 (COM4) instead of 0x3f8 -- it's expected
* that this is safe since a real port responds correctly and a
* missing port will respond with 0xff which will terminate the
* loop that waits for the "right" status on the port.
*/
movw $0x2e8, %cs:serial_port_base_address
resize_end:
/* clear (hopefully) overwritten cursor position buffer */
xorb %al, %al
movw $BDA_CURSOR_BUF, %di
movw $0x10, %cx
cld
rep
stosb /* fill 40:50 - 40:5f with 0 */
pushw %cs
popw %ds /* ds = cs */
call get_byte /* flush any remaining "wrong" input */
jnz resize_end
call send_crlf /* place cursor on start of last line */
movw $mfg_string, %si
call send_asciz_out
call send_crlf
movw $prod_string, %si
call send_asciz_out
call send_crlf
movw $long_version, %si
call send_asciz_out
call send_crlf
/* if vga attached, skip terminal message and bda setup... */
cmpw $0xc000, %cs:old_int10h_seg /* vga attached? */
jz post_bda_init_tail /* if so, don't modify BDA */
/* show detected terminal size, or default if none detected */
movw $term_info, %si
call send_asciz_out
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb %cs:term_cols, %al
movb %al, BDA_COLS /* 40:4a = number of character cols */
movb $0, BDA_CURSOR_COL /* 40:51 = cursor0 col */
call send_number
movb $0x78, %al /* x */
call send_byte
movb %cs:term_rows, %al
movb %al, %ah
decb %ah /* ah = rows-1 */
movb %ah, BDA_ROWS /* 40:84 = num character rows - 1 */
movb %ah, BDA_CURSOR_ROW /* 40:50 = cursor0 row */
call send_number
call send_crlf
movb $3, BDA_MODE_NUM
movb $0x29, BDA_MODE_SEL
movw $VGA_IO_BASE, BDA_6845_ADDR
movw $0x4000, BDA_PAGE_SIZE /* 16KB per video page */
/* to avoid ansi colors every character, store last attribute */
movb $0x07, BDA_COLOR_VAL /* 07 = black bg, white fg */
movw %cs, %ax
movw $_start, BDA_ROM_OFF
movw %ax, BDA_ROM_SEG
post_bda_init_tail:
/* copy BDA rows/cols to sgabios location... */
/* if vga card is installed, reuse those values... */
/* if no vga card is installed, this shouldn't change anything */
pushw $BDA_SEG
popw %ds /* ds = 0x40 */
movb BDA_ROWS, %al
incb %al /* bda holds rows-1 */
movb %al, %cs:term_rows /* sgabios rows */
movb BDA_COLS, %ah
movb %ah, %cs:term_cols /* sgabios cols */
/* setup in-memory logging of console if desired... */
call setup_memconsole
/* setup logging of last 256 characters output, if ebda has room */
call sgabioslog_setup_ebda
movw $ebda_info, %si
call send_asciz_out
movw %cs:sgabios_ebda_logbuf_offset, %ax
xchgb %ah, %al
call send_number
movb $0x20, %al
call send_byte
movb %ah, %al
call send_number
call send_crlf
popw %es
popw %ds
popaw
popf
lret
_end_sgabios:
|