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
|
; $Id: orgs.asm $
;; @file
; ???
;
;
; Copyright (C) 2006-2023 Oracle and/or its affiliates.
;
; This file is part of VirtualBox base platform packages, as
; available from https://www.virtualbox.org.
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation, in version 3 of the
; License.
;
; This program is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, see <https://www.gnu.org/licenses>.
;
; SPDX-License-Identifier: GPL-3.0-only
; --------------------------------------------------------------------
;
; This code is based on:
;
; ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
;
; Copyright (C) 2002 MandrakeSoft S.A.
;
; MandrakeSoft S.A.
; 43, rue d'Aboukir
; 75002 Paris - France
; http://www.linux-mandrake.com/
; http://www.mandrakesoft.com/
;
; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Lesser General Public
; License as published by the Free Software Foundation; either
; version 2 of the License, or (at your option) any later version.
;
; This library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General Public
; License along with this library; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;
; Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
; other than GPL or LGPL is available it will apply instead, Oracle elects to use only
; the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
; a choice of LGPL license versions is made available with the language indicating
; that LGPLv2 or any later version may be used, or where a choice of which version
; of the LGPL is applied is otherwise unspecified.
include commondefs.inc
EBDA_SIZE equ 1 ; 1K minimum -- other modules may add to it
CMOS_ADDR equ 070h
CMOS_DATA equ 071h
PIC_CMD_EOI equ 020h
PIC_MASTER equ 020h
PIC_SLAVE equ 0A0h
BIOS_FIX_BASE equ 0E000h
if VBOX_BIOS_CPU ge 80286
SYS_MODEL_ID equ 0FCh ; PC/AT
SYS_SUBMODEL_ID equ 1
else
SYS_MODEL_ID equ 0FBh ; PC/XT
SYS_SUBMODEL_ID equ 0
endif
BIOS_REVISION equ 1
BIOS_BUILD_DATE equ '06/23/99'
BIOS_COPYRIGHT equ 'Oracle VM VirtualBox BIOS'
BX_ROMBIOS32 equ 0
BX_CALL_INT15_4F equ 1
;; Set a fixed BIOS location, with a marker for verification
BIOSORG macro addr, addr_minus_two
.errnz (addr - 2 - addr_minus_two) ;; Couldn't convince wasm to accept $ here. Would've save us a lot of bother and ugly SED.
BIOSORG_CHECK_BEFORE addr_minus_two
org addr - BIOS_FIX_BASE - 2
db 'XM'
BIOSORG_CHECK addr
endm
;; Set an interrupt vector (not very efficient if multiple vectors are
;; programmed in one go)
SET_INT_VECTOR macro vec, segm, offs
mov ax, offs
mov ds:[vec*4], ax
mov ax, segm
mov ds:[vec*4+2], ax
endm
; Set up an environment C code expects. DS must point to the BIOS segment
; and the direction flag must be cleared(!)
C_SETUP macro
push cs
pop ds
cld
endm
;; External function in separate modules
extrn _dummy_isr_function:near
extrn _log_bios_start:near
extrn _nmi_handler_msg:near
extrn _int18_panic_msg:near
extrn _int09_function:near
extrn _int13_diskette_function:near
extrn _int13_eltorito:near
extrn _int13_cdemu:near
extrn _int13_cdrom:near
extrn _cdemu_isactive:near
extrn _cdemu_emulated_drive:near
extrn _int13_harddisk:near
extrn _int13_harddisk_ext:near
extrn _int14_function:near
extrn _int15_function:near
extrn _int15_function_mouse:near
extrn _int16_function:near
extrn _int17_function:near
extrn _int19_function:near
extrn _int1a_function:near
extrn _pci16_function:near
extrn _int70_function:near
extrn _int74_function:near
extrn _apm_function:near
extrn _ata_init:near
extrn _scsi_init:near
extrn _ata_detect:near
extrn _cdemu_init:near
extrn _keyboard_init:near
extrn _print_bios_banner:near
extrn _inv_op_handler:near
extrn rom_scan_:near
ifdef VBOX_WITH_AHCI
extrn _ahci_init:near
endif
if VBOX_BIOS_CPU ge 80286
extrn _int15_blkmove:near
endif
if VBOX_BIOS_CPU ge 80386
extrn _int15_function32:near
extrn _apic_setup:near
endif
;; Symbols referenced from C code
public _diskette_param_table
public _pmode_IDT
public _rmode_IDT
public post
public eoi_both_pics
public rtc_post
;; Additional publics for easier disassembly and debugging
ifndef DEBUG
DEBUG equ 1
endif
ifdef DEBUG
public int08_handler
public int0e_handler
public int11_handler
public int12_handler
public int13_handler
public int13_relocated
if VBOX_BIOS_CPU eq 8086
public jmp_call_ret_int13_out
endif
public int15_handler
public int17_handler
public int19_handler
public int19_relocated
public dummy_iret
public nmi
public rom_fdpt
public cpu_reset
public normal_post
public eoi_jmp_post
public no_eoi_jmp_post
public eoi_master_pic
public ebda_post
public seg_40_value
public hard_drive_post
public int13_legacy
public int70_handler
public int75_handler
public int15_handler32
public int15_handler_mouse
public iret_modify_cf
public init_pic
public floppy_post
public int13_out
public int13_disk
public int13_notfloppy
public int13_legacy
public int13_noeltorito
public int1c_handler
public int10_handler
public int74_handler
public int76_handler
public detect_parport
public detect_serial
public font8x8
endif
;; Keyboard related constants
KBDC_DISABLE EQU 0ADh
KBDC_ENABLE EQU 0AEh
KBC_CMD EQU 64h
KBC_DATA EQU 60h
;; NOTE: The last 8K of the ROM BIOS are peppered with fixed locations which
;; must be retained for compatibility. As a consequence, some of the space is
;; going to be wasted, but the gaps should be filled with miscellaneous code
;; and data when possible.
SET_DEFAULT_CPU_286
BIOSSEG segment 'CODE'
assume cs:BIOSSEG
;;
;; Start of fixed code - eoi_jmp_post is kept near here to allow short jumps.
;;
BIOSORG 0E030h, 0E02Eh
eoi_both_pics:
mov al, PIC_CMD_EOI
out PIC_SLAVE, al
eoi_master_pic:
mov al, PIC_CMD_EOI
out PIC_MASTER, al
ret
;; routine to write the pointer in DX:AX to memory starting
;; at DS:BX (repeat CX times)
;; - modifies BX, CX
set_int_vects proc near
mov [bx], ax
mov [bx+2], dx
add bx, 4
loop set_int_vects
ret
set_int_vects endp
eoi_jmp_post:
;; Calling eoi_both_pics can't be done because it writes to stack, potentially
;; corrupting memory. AT BIOS also only clears the master PIC, not both.
;; clear keyboard buffer (and possible interrupt)
in al, KBC_DATA
mov al, PIC_CMD_EOI
out PIC_MASTER, al
no_eoi_jmp_post:
mov ax, 40h
mov ds, ax
jmp dword ptr ds:[67h]
seg_40_value: dw 40h ;; Replaces a push 40; pop ds.
;; --------------------------------------------------------
;; POST entry point
;; --------------------------------------------------------
BIOSORG 0E05Bh, 0E059h
post:
cli
if VBOX_BIOS_CPU ge 80286
;; Check if in protected (V86) mode. If so, the CPU needs
;; to be reset.
.286p
smsw ax
test ax, 1
jz in_real_mode
SET_DEFAULT_CPU_286
else
jmp in_real_mode
endif
;; Reset processor to get out of protected mode. Use system
;; port instead of KBC.
reset_sys:
mov al, 1
out 92h, al
jmp $ ; not strictly necessary in a VM
in_real_mode:
;; read the CMOS shutdown status
mov al, 0Fh
out CMOS_ADDR, al
in al, CMOS_DATA
;; save status
xchg ah, al
;; Check KBC self-test/shutdown flag. If it is set, we need
;; to check for a reboot attempt.
in al, 64h
test al, 4 ; clear flag indicates cold boot
jz cont_post
;; Warm boot, check the shutdown byte.
mov al, ah
or al, al
jnz cont_post
;; Warm boot but shutdown byte is zero. This is either a warm
;; boot request or an attempt to reset the system via triple
;; faulting the CPU or similar. Check reboot flag.
;; NB: At this point, registers need not be preserved.
mov ds, cs:[seg_40_value]
cmp word ptr ds:[72h], 1234h
jnz reset_sys ; trigger system reset
cont_post:
;; reset the shutdown status in CMOS
mov al, 0Fh
out CMOS_ADDR, al
mov al, 0
out CMOS_DATA, al
;; pre-check the shutdown status - shutdown codes 9/A leave
;; the hardware alone
mov al, ah
cmp al, 09h
jz check_shutdown
cmp al, 0Ah
jz check_shutdown
xor al, al
;; reset the DMA controllers
out 00Dh, al
out 0DAh, al
;; then initialize the DMA controllers
mov al, 0C0h
out 0D6h, al ; enable channel 4 cascade
mov al, 0
out 0D4h, al ; unmask channel 4
check_shutdown:
;; examine the shutdown status code
mov al, ah
cmp al, 0
jz normal_post
cmp al, 0Dh
jae normal_post
cmp al, 9
jne check_next_std
jmp return_blkmove
check_next_std:
mov sp, 400h
;; 05h = EOI + jump through 40:67
cmp al, 5
je eoi_jmp_post
;; 0ah = jump through 40:67 (no EOI) ;ba x 1 %fe05b ; ba x 1 %18b81
cmp al, 0ah
je no_eoi_jmp_post
;; any other shutdown status values are ignored
;; OpenSolaris sets the status to 0Ah in some cases?
jmp normal_post
normal_post:
;; shutdown code 0: normal startup
;; Set up the stack top at 0:7800h. The stack should not be
;; located above 0:7C00h; that conflicts with PXE, which
;; considers anything above that address to be fair game.
;; The traditional locations are 30:100 (PC) or 0:400 (PC/AT).
mov ax, 7800h
mov sp, ax
xor ax, ax
mov ds, ax
mov ss, ax
;; clear the bottom of memory except for the word at 40:72
;; TODO: Why not clear all of it? What's the point?
mov es, ax
xor di, di
cld
mov cx, 0472h / 2
rep stosw
inc di
inc di
mov cx, (1000h - 0472h - 2) / 2
rep stosw
;; clear the remaining base memory except for the top
;; of the EBDA (the MP table is planted there)
xor bx, bx
memory_zero_loop:
add bx, 1000h
cmp bx, 9000h
jae memory_cleared
mov es, bx
xor di, di
mov cx, 8000h ; 32K words
rep stosw
jmp memory_zero_loop
memory_cleared:
mov es, bx
xor di, di
mov cx, 7FF8h ; all but the last 16 bytes
rep stosw
xor bx, bx
C_SETUP
call _log_bios_start
if VBOX_BIOS_CPU ge 80386
call pmode_setup
endif
;; set all interrupts in 00h-5Fh range to default handler
xor bx, bx
mov ds, bx
mov cx, 60h ; leave the rest as zeros
mov ax, dummy_iret
mov dx, BIOSSEG
call set_int_vects
;; also set 68h-77h to default handler; note that the
;; 60h-67h range must contain zeros for certain programs
;; to function correctly
mov bx, 68h * 4
mov cx, 10h
call set_int_vects
;; base memory in K to 40:13
mov al, 16h
out CMOS_ADDR, al
in al, CMOS_DATA
mov ah, al
mov al, 15h
out CMOS_ADDR, al
in al, CMOS_DATA
sub ax, EBDA_SIZE
mov ds:[413h], ax
;; manufacturing test at 40:12
;; zeroed out above
;; set up various service vectors
;; TODO: This should use the table at FEF3h instead
SET_INT_VECTOR 06h, BIOSSEG, int06_handler
SET_INT_VECTOR 11h, BIOSSEG, int11_handler
SET_INT_VECTOR 12h, BIOSSEG, int12_handler
SET_INT_VECTOR 15h, BIOSSEG, int15_handler
SET_INT_VECTOR 17h, BIOSSEG, int17_handler
SET_INT_VECTOR 18h, BIOSSEG, int18_handler
SET_INT_VECTOR 19h, BIOSSEG, int19_handler
SET_INT_VECTOR 1Ch, BIOSSEG, int1c_handler
call ebda_post
;; Initialize PCI devices. This can and should be done early.
if VBOX_BIOS_CPU ge 80386 ; (Impossible to do on 16-bit CPUs.)
call pcibios_init_iomem_bases
call pcibios_init_irqs
endif
SET_INT_VECTOR 1Ah, BIOSSEG, int1a_handler
;; PIT setup
SET_INT_VECTOR 08h, BIOSSEG, int08_handler
mov al, 34h ; timer 0, binary, 16-bit, mode 2
out 43h, al
mov al, 0 ; max count -> ~18.2 Hz
out 40h, al
out 40h, al
;; video setup - must be done before POSTing VGA ROM
SET_INT_VECTOR 10h, BIOSSEG, int10_handler
;; keyboard setup
SET_INT_VECTOR 09h, BIOSSEG, int09_handler
SET_INT_VECTOR 16h, BIOSSEG, int16_handler
xor ax, ax
mov ds, ax
mov al, 10h
mov ds:[496h], al ; keyboard status flags 3
mov bx, 1Eh
mov ds:[41Ah], bx ; keyboard buffer head
mov ds:[41Ch], bx ; keyboard buffer tail
mov ds:[480h], bx ; keyboard buffer start
mov bx, 3Eh
mov ds:[482h], bx ; keyboard buffer end
;; store CMOS equipment byte in BDA
mov al, 14h
out CMOS_ADDR, al
in al, CMOS_DATA
mov ds:[410h], al
push ds
C_SETUP
;; Scan for video ROMs in the C000-C800 range. This is done
;; early so that errors are displayed on the screen.
mov ax, 0C000h
mov dx, 0C800h
call rom_scan_
;; Initialize the keyboard
call _keyboard_init
pop ds
;; parallel setup
SET_INT_VECTOR 0Fh, BIOSSEG, dummy_iret
xor ax, ax
mov ds, ax
xor bx, bx
mov cl, 14h ; timeout value
mov dx, 378h ; parallel port 1
call detect_parport
mov dx, 278h ; parallel port 2
call detect_parport
DO_shl bx, 0Eh
mov ax, ds:[410h] ; equipment word
and ax, 3FFFh
or ax, bx ; set number of parallel ports
mov ds:[410h], ax ; store in BDA
;; Serial setup
SET_INT_VECTOR 0Bh, BIOSSEG, dummy_isr ; IRQ 3
SET_INT_VECTOR 0Ch, BIOSSEG, dummy_isr ; IRQ 4
SET_INT_VECTOR 14h, BIOSSEG, int14_handler
xor bx, bx
mov cl, 0Ah ; timeout value
mov dx, 3F8h ; first serial address
call detect_serial
mov dx, 2F8h ; second serial address
call detect_serial
mov dx, 3E8h ; third serial address
call detect_serial
mov dx, 2E8h ; fourth serial address
call detect_serial
DO_shl bx, 9
mov ax, ds:[410h] ; equipment word
and ax, 0F1FFh ; bits 9-11 determine serial ports
or ax, bx
mov ds:[410h], ax
;; CMOS RTC
SET_INT_VECTOR 4Ah, BIOSSEG, dummy_iret ; TODO: redundant?
SET_INT_VECTOR 70h, BIOSSEG, int70_handler
;; BIOS DATA AREA 4CEh ???
call rtc_post
jmp norm_post_cont
;; --------------------------------------------------------
;; NMI handler
;; --------------------------------------------------------
BIOSORG 0E2C3h, 0E2C1h
nmi:
C_SETUP
call _nmi_handler_msg
iret
int75_handler:
out 0F0h, al ; clear IRQ13
call eoi_both_pics
int 2 ; emulate legacy NMI
iret
hard_drive_post proc near
xor ax, ax
mov ds, ax
;; TODO: Didn't we just clear the entire EBDA?
mov ds:[474h], al ; last HD operation status
mov ds:[477h], al ; HD port offset (XT only???)
mov ds:[48Ch], al ; HD status register
mov ds:[48Dh], al ; HD error register
mov ds:[48Eh], al ; HD task complete flag
mov al, 0C0h
mov ds:[476h], al ; HD control byte
;; set up hard disk interrupt vectors
SET_INT_VECTOR 13h, BIOSSEG, int13_handler
SET_INT_VECTOR 76h, BIOSSEG, int76_handler
;; The ATA init code sets up INT 41h/46h FDPT pointers
ret
hard_drive_post endp
norm_post_cont:
;; PS/2 mouse setup
SET_INT_VECTOR 74h, BIOSSEG, int74_handler
;; IRQ 13h (FPU exception) setup
SET_INT_VECTOR 75h, BIOSSEG, int75_handler
call init_pic
C_SETUP
if VBOX_BIOS_CPU ge 80386
;; Set up local APIC
.386
pushad
call _apic_setup
popad
SET_DEFAULT_CPU_286
endif
;; ATA/ATAPI driver setup
call _ata_init
call _ata_detect
ifdef VBOX_WITH_AHCI
; AHCI driver setup
;; TODO: AHCI initialization needs timer, but enabling
;; interrupts elsewhere may be risky. Just do it around
;; the AHCI init.
sti
call _ahci_init
cli
endif
ifdef VBOX_WITH_SCSI
; SCSI driver setup
call _scsi_init
endif
;; floppy setup
call floppy_post
;; hard drive setup
call hard_drive_post
C_SETUP ; in case assembly code changed things
;; Scan for additional ROMs in the C800-EFFF range
mov ax, 0C800h
mov dx, 0F000h
call rom_scan_
if VBOX_BIOS_CPU ge 80386
;; The POST code does not bother preserving high bits of the
;; 32-bit registers. Now is a good time to clear them so that
;; there's no garbage left in high bits.
.386
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
.286
endif
call _print_bios_banner
;; El Torito floppy/hard disk emulation
call _cdemu_init
; TODO: what's the point of enabling interrupts here??
sti ; enable interrupts
int 19h
;; does not return here
sti
wait_forever:
hlt
jmp wait_forever
cli
hlt
;;
;; Return from block move (shutdown code 09h). Care must be taken to disturb
;; register and memory state as little as possible.
;;
return_blkmove:
.286p
mov ax, 40h
mov ds, ax
;; restore user stack
mov ss, ds:[69h]
mov sp, ds:[67h]
;; reset A20 gate
in al, 92h
and al, 0FDh
out 92h, al
;; ensure proper real mode IDT
lidt fword ptr cs:_rmode_IDT
;; restore user segments
pop ds
pop es
;; set up BP
mov bp, sp
;; restore status code
in al, 80h
mov [bp+15], al
;; set ZF/CF
cmp ah,al ; AH is zero here!
;; restore registers and return
popa
sti
retf 2
SET_DEFAULT_CPU_286
;; --------------------------------------------------------
;; INT 13h handler - Disk services
;; --------------------------------------------------------
BIOSORG 0E3FEh, 0E3FCh
int13_handler:
jmp int13_relocated
;; Fixed disk table entry
fd_entry struc
cyls dw ? ; Cylinders
heads db ? ; Heads
res_1 dw ?
wpcomp dw ? ; Write pre-compensation start cylinder
res_2 db ?
ctrl db ? ; Control byte
res_3 db ?
res_4 db ?
res_5 db ?
lzone dw ? ; Landing zone cylinder
spt db ? ; Sectors per track
res_6 db ?
fd_entry ends
;; --------------------------------------------------------
;; Fixed Disk Parameter Table
;; --------------------------------------------------------
BIOSORG_CHECK 0E401h ; fixed wrt preceding
rom_fdpt:
fd_entry < 306, 4, 0, 128, 0, 0, 0, 0, 0, 305, 17, 0> ; Type 1, 10 MB
fd_entry < 615, 4, 0, 300, 0, 0, 0, 0, 0, 615, 17, 0> ; Type 2, 20 MB
fd_entry < 615, 6, 0, 300, 0, 0, 0, 0, 0, 615, 17, 0> ; Type 3, 30 MB
fd_entry < 940, 8, 0, 512, 0, 0, 0, 0, 0, 940, 17, 0> ; Type 4, 62 MB
fd_entry < 940, 6, 0, 512, 0, 0, 0, 0, 0, 940, 17, 0> ; Type 5, 46 MB
fd_entry < 615, 4, 0, -1, 0, 0, 0, 0, 0, 615, 17, 0> ; Type 6, 20 MB
fd_entry < 462, 8, 0, 256, 0, 0, 0, 0, 0, 511, 17, 0> ; Type 7, 31 MB
fd_entry < 733, 5, 0, -1, 0, 0, 0, 0, 0, 733, 17, 0> ; Type 8, 30 MB
fd_entry < 900, 15, 0, -1, 0, 8, 0, 0, 0, 901, 17, 0> ; Type 9, 112 MB
fd_entry < 820, 3, 0, -1, 0, 0, 0, 0, 0, 820, 17, 0> ; Type 10, 20 MB
fd_entry < 855, 5, 0, -1, 0, 0, 0, 0, 0, 855, 17, 0> ; Type 11, 35 MB
fd_entry < 855, 7, 0, -1, 0, 0, 0, 0, 0, 855, 17, 0> ; Type 12, 49 MB
fd_entry < 306, 8, 0, 128, 0, 0, 0, 0, 0, 319, 17, 0> ; Type 13, 20 MB
fd_entry < 733, 7, 0, -1, 0, 0, 0, 0, 0, 733, 17, 0> ; Type 14, 42 MB
fd_entry < 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0> ; Reserved
fd_entry < 612, 4, 0, -1, 0, 0, 0, 0, 0, 633, 17, 0> ; Type 16, 20 MB
fd_entry < 977, 5, 0, 300, 0, 0, 0, 0, 0, 977, 17, 0> ; Type 17, 40 MB
fd_entry < 977, 7, 0, -1, 0, 0, 0, 0, 0, 977, 17, 0> ; Type 18, 56 MB
fd_entry <1024, 7, 0, 512, 0, 0, 0, 0, 0,1023, 17, 0> ; Type 19, 59 MB
fd_entry < 733, 5, 0, 300, 0, 0, 0, 0, 0, 732, 17, 0> ; Type 20, 30 MB
fd_entry < 733, 7, 0, 300, 0, 0, 0, 0, 0, 732, 17, 0> ; Type 21, 42 MB
fd_entry < 733, 5, 0, 300, 0, 0, 0, 0, 0, 733, 17, 0> ; Type 22, 30 MB
fd_entry < 306, 4, 0, 0, 0, 0, 0, 0, 0, 336, 17, 0> ; Type 23, 10 MB
;; --------------------------------------------------------
;; INT 19h handler - Boot load service
;; --------------------------------------------------------
BIOSORG 0E6F2h, 0E6F0h
int19_handler:
jmp int19_relocated
;; --------------------------------------------------------
;; System BIOS Configuration Table
;; --------------------------------------------------------
BIOSORG_CHECK 0E6F5h ; fixed wrt preceding
; must match BIOS_CONFIG_TABLE
bios_cfg_table:
dw 9 ; table size in bytes
db SYS_MODEL_ID
db SYS_SUBMODEL_ID
db BIOS_REVISION
; Feature byte 1
; b7: 1=DMA channel 3 used by hard disk
; b6: 1=2 interrupt controllers present
; b5: 1=RTC present
; b4: 1=BIOS calls int 15h/4Fh for every key
; b3: 1=wait for extern event supported (Int 15h/41h)
; b2: 1=extended BIOS data area used
; b1: 0=AT or ESDI bus, 1=MicroChannel
; b0: 1=Dual bus (MicroChannel + ISA)
ifdef BX_CALL_INT15_4F
db 74h; or USE_EBDA
else
db 64h; or USE_EBDA
endif
; Feature byte 2
; b7: 1=32-bit DMA supported
; b6: 1=int16h, function 9 supported
; b5: 1=int15h/C6h (get POS data) supported
; b4: 1=int15h/C7h (get mem map info) supported
; b3: 1=int15h/C8h (en/dis CPU) supported
; b2: 1=non-8042 kb controller
; b1: 1=data streaming supported
; b0: reserved
db 40h
; Feature byte 3
; b7: not used
; b6: reserved
; b5: reserved
; b4: POST supports ROM-to-RAM enable/disable
; b3: SCSI on system board
; b2: info panel installed
; b1: Initial Machine Load (IML) system - BIOS on disk
; b0: SCSI supported in IML
db 0
; Feature byte 4
; b7: IBM private
; b6: EEPROM present
; b5-3: ABIOS presence (011 = not supported)
; b2: private
; b1: memory split above 16Mb supported
; b0: POSTEXT directly supported by POST
db 0
; Feature byte 5 (IBM)
; b1: enhanced mouse
; b0: flash EPROM
db 0
;; --------------------------------------------------------
;; Baud Rate Generator Table
;; --------------------------------------------------------
BIOSORG 0E729h, 0E727h
;; --------------------------------------------------------
;; INT 14h handler - Serial Communication Service
;; --------------------------------------------------------
BIOSORG 0E739h, 0E737h
int14_handler:
push ds
push es
DO_pusha
C_SETUP
call _int14_function
DO_popa
pop es
pop ds
iret
;;
;; Handler for unexpected hardware interrupts
;;
dummy_isr:
push ds
push es
DO_pusha
C_SETUP
call _dummy_isr_function
DO_popa
pop es
pop ds
iret
init_pic proc near
mov al, 11h ; send init commands
out PIC_MASTER, al
out PIC_SLAVE, al
mov al, 08h ; base 08h
out PIC_MASTER+1, al
mov al, 70h ; base 70h
out PIC_SLAVE+1, al
mov al, 04h ; master PIC
out PIC_MASTER+1, al
mov al, 02h ; slave PIC
out PIC_SLAVE+1, al
mov al, 01h
out PIC_MASTER+1, al
out PIC_SLAVE+1, al
mov al, 0B8h ; unmask IRQs 0/1/2/6
out PIC_MASTER+1, al
mov al, 08Fh
out PIC_SLAVE+1, al ; unmask IRQs 12/13/14
ret
init_pic endp
ebda_post proc near
SET_INT_VECTOR 0Dh, BIOSSEG, dummy_isr ; IRQ 5
SET_INT_VECTOR 0Fh, BIOSSEG, dummy_isr ; IRQ 7
SET_INT_VECTOR 72h, BIOSSEG, dummy_isr ; IRQ 10
SET_INT_VECTOR 73h, BIOSSEG, dummy_isr ; IRQ 11
SET_INT_VECTOR 77h, BIOSSEG, dummy_isr ; IRQ 15
;; calculate EBDA segment
xor ax, ax
mov ds, ax
mov ax, ds:[413h] ; conventional memory size minus EBDA size
mov cx, 64 ; 64 paras per KB
mul cx
;; store EBDA seg in 40:0E
mov word ptr ds:[40Eh], ax
;; store EBDA size in the first word of EBDA
mov ds, ax
mov byte ptr ds:[0], EBDA_SIZE
;; must reset DS to zero again
xor ax, ax
mov ds, ax
ret
ebda_post endp
;; --------------------------------------------------------
;; INT 16h handler - Keyboard service
;; --------------------------------------------------------
BIOSORG 0E82Eh, 0E82Ch
int16_handler:
sti
;; Flags are saved *after* enabling interrupts, and with
;; implicitly cleared TF. Software may depend on that.
pushf
push es
push ds
DO_pusha
cmp ah, 0
je int16_F00
cmp ah, 10h
je int16_F00
C_SETUP
call _int16_function
DO_popa
pop ds
pop es
add sp, 2 ; Skip saved flags
iret
int16_F00:
mov bx, 40h ; TODO: why 40h here and 0 elsewhere?
mov ds, bx
int16_wait_for_key:
cli
mov bx, ds:[1Ah]
cmp bx, ds:[1Ch]
jne int16_key_found
sti
nop
; TODO: review/enable?
if 0
push ax
mov ax, 9002h
int 15h
pop ax
endif
jmp int16_wait_for_key
int16_key_found:
C_SETUP
call _int16_function
DO_popa
pop ds
pop es
add sp, 2 ; Skip saved flags
; TODO: review/enable? If so, flags should be restored here?
if 0
push ax
mov ax, 9202h
int 15h
pop ax
endif
iret
if VBOX_BIOS_CPU ge 80386
;; Quick and dirty protected mode entry/exit routines
include pmode.inc
;; Initialization code which needs to run in protected mode (LAPIC etc.)
include pmsetup.inc
endif
;; --------------------------------------------------------
;; INT 09h handler - Keyboard ISR (IRQ 1)
;; --------------------------------------------------------
BIOSORG 0E987h, 0E985h
int09_handler:
cli ; TODO: why? they're off already!
push ax
mov al, KBDC_DISABLE
out KBC_CMD, al
in al, KBC_DATA
push ds
DO_pusha
cld ; Before INT 15h (and any C code)
ifdef BX_CALL_INT15_4F
mov ah, 4Fh
stc
int 15h ; keyboard intercept
jnc int09_done
endif
sti ; Only after calling INT 15h
;; check for extended key
cmp al, 0E0h
jne int09_check_pause
xor ax, ax
mov ds, ax
or byte ptr ds:[496h], 2 ; mf2_state |= 0x02
jmp int09_done
int09_check_pause:
cmp al, 0E1h ; pause key?
jne int09_process_key
xor ax, ax
mov ds, ax
or byte ptr ds:[496h], 1 ; mf2_state | 0x01
jmp int09_done
int09_process_key:
push es
C_SETUP
call _int09_function
pop es
int09_done:
DO_popa
pop ds
cli
call eoi_master_pic
mov al, KBDC_ENABLE
out KBC_CMD, al
pop ax
iret
;; --------------------------------------------------------
;; INT 06h handler - Invalid Opcode Exception
;; --------------------------------------------------------
int06_handler:
DO_pusha
push es
push ds
C_SETUP
call _inv_op_handler
pop ds
pop es
DO_popa
iret
;; --------------------------------------------------------
;; INT 13h handler - Diskette service
;; --------------------------------------------------------
BIOSORG 0EC59h, 0EC57h
int13_diskette:
jmp int13_noeltorito
;; --------------------------------------------------------
;; INT 13h handler - Disk service
;; --------------------------------------------------------
int13_relocated:
;; check for an El-Torito function
cmp ah, 4Ah
jb int13_not_eltorito
cmp ah, 4Dh
ja int13_not_eltorito
DO_pusha
push es
push ds
C_SETUP ; TODO: setup C envrionment only once?
DO_JMP_CALL_EX _int13_eltorito, int13_out, jmp_call_ret_int13_out ; ELDX not used
if VBOX_BIOS_CPU eq 8086
jmp_call_ret_int13_out: dw offset int13_out
endif
int13_not_eltorito:
push es
push ax ; TODO: better register save/restore
push bx
push cx
push dx
;; check if emulation is active
call _cdemu_isactive
cmp al, 0
je int13_cdemu_inactive
;; check if access to the emulated drive
call _cdemu_emulated_drive
pop dx ; recover dx (destroyed by C code)
push dx
cmp al, dl ; INT 13h on emulated drive
jne int13_nocdemu
pop dx
pop cx
pop bx
pop ax
pop es
DO_pusha
push es
push ds
C_SETUP ; TODO: setup environment only once?
DO_JMP_CALL_EX _int13_cdemu, int13_out, jmp_call_ret_int13_out ; ELDX not used
int13_nocdemu:
and dl, 0E0h ; mask to get device class
cmp al, dl
jne int13_cdemu_inactive
pop dx
pop cx
pop bx
pop ax
pop es
push ax
push cx
push dx
push bx
dec dl ; real drive is dl - 1
jmp int13_legacy
int13_cdemu_inactive:
pop dx
pop cx
pop bx
pop ax
pop es
int13_noeltorito:
push ax
push cx
push dx
push bx
int13_legacy:
push dx ; push eltorito dx in place of sp
push bp
push si
push di
push es
push ds
C_SETUP ; TODO: setup environment only once?
;; now the registers can be restored with
;; pop ds; pop es; DO_popa; iret
test dl, 80h ; non-removable?
jnz int13_notfloppy
DO_JMP_CALL_EX _int13_diskette_function, int13_out, jmp_call_ret_int13_out
int13_notfloppy:
cmp dl, 0E0h
jb int13_notcdrom
;; ebx may be modified, save here
;; TODO: check/review 32-bit register use
;; @todo figure if 80286/8086 variant is applicable.
.386
shr ebx, 16
push bx
call _int13_cdrom
pop bx
shl ebx, 16
SET_DEFAULT_CPU_286
jmp int13_out
int13_notcdrom:
int13_disk:
cmp ah,40h
ja int13x
call _int13_harddisk
jmp int13_out
int13x:
call _int13_harddisk_ext
int13_out:
pop ds
pop es
DO_popa
iret
; parallel port detection: port in dx, index in bx, timeout in cl
detect_parport proc near
push dx
inc dx
inc dx
in al, dx
and al, 0DFh ; clear input mode
out dx, al
pop dx
mov al, 0AAh
out dx, al
in al, dx
cmp al, 0AAh
jne no_parport
push bx
shl bx, 1
mov [bx+408h], dx ; parallel I/O address
pop bx
mov [bx+478h], cl ; parallel printer timeout
inc bx
no_parport:
ret
detect_parport endp
; setial port detection: port in dx, index in bx, timeout in cl
detect_serial proc near
push dx
inc dx
mov al, 2
out dx, al
in al, dx
cmp al, 2
jne no_serial
inc dx
in al, dx
cmp al, 2
jne no_serial
dec dx
xor al, al
pop dx
push bx
shl bx, 1
mov [bx+400h], dx ; serial I/O address
pop bx
mov [bx+47Ch], cl ; serial timeout
inc bx
ret
no_serial:
pop dx
ret
detect_serial endp
;;
;; POST: Floppy drive
;;
floppy_post proc near
xor ax, ax
mov ds, ax
;; TODO: This code is really stupid. Zeroing the BDA byte
;; by byte is dumb, and it's been already zeroed elsewhere!
mov al, 0
mov ds:[43Eh], al ; drive 0/1 uncalibrated, no IRQ
mov ds:[43Fh], al ; motor status
mov ds:[440h], al ; motor timeout counter
mov ds:[441h], al ; controller status return code
mov ds:[442h], al ; hd/floppy ctlr status register
mov ds:[443h], al ; controller status register 1
mov ds:[444h], al ; controller status register 2
mov ds:[445h], al ; cylinder number
mov ds:[446h], al ; head number
mov ds:[447h], al ; sector number
mov ds:[448h], al ; bytes written
mov ds:[48Bh], al ; configuration data
mov al, 10h ; floppy drive type
out CMOS_ADDR, al
in al, CMOS_DATA
mov ah, al ; save drive type byte
look_drive0:
; TODO: pre-init bl to reduce jumps
DO_shr al, 4 ; drive 0 in high nibble
jz f0_missing ; jump if no drive
mov bl, 7 ; drv0 determined, multi-rate, chgline
jmp look_drive1
f0_missing:
mov bl, 0 ; no drive 0
look_drive1:
mov al, ah ; restore CMOS data
and al, 0Fh ; drive 1 in low nibble
jz f1_missing
or bl, 70h ; drv1 determined, multi-rate, chgline
f1_missing:
mov ds:[48Fh], bl ; store in BDA
;; TODO: See above. Dumb *and* redundant!
mov al, 0
mov ds:[490h], al ; drv0 media state
mov ds:[491h], al ; drv1 media state
mov ds:[492h], al ; drv0 operational state
mov ds:[493h], al ; drv1 operational state
mov ds:[494h], al ; drv0 current cylinder
mov ds:[495h], al ; drv1 current cylinder
mov al, 2
out 0Ah, al ; unmask DMA channel 2
SET_INT_VECTOR 1Eh, BIOSSEG, _diskette_param_table
SET_INT_VECTOR 40h, BIOSSEG, int13_diskette
SET_INT_VECTOR 0Eh, BIOSSEG, int0e_handler ; IRQ 6
ret
floppy_post endp
bcd_to_bin proc near
;; in : AL in packed BCD format
;; out: AL in binary, AH always 0
if VBOX_BIOS_CPU ge 80186
shl ax, 4
shr al, 4
else
push cx
mov cl, 4
shl ax, cl
shr al, cl
pop cx
endif
aad
ret
bcd_to_bin endp
rtc_post proc near
if VBOX_BIOS_CPU lt 80386 ;; @todo fix loopy code below
;; get RTC seconds
mov al, 0
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC seconds, in BCD
call bcd_to_bin ; ax now has seconds in binary
test al, al
xor ah, ah
mov dx, 0x1234 ; 18206507*0x100/1000000 = 0x1234 (4660.865792)
mul dx
mov cx, ax ; tick count in dx:cx
;; get RTC minutes
mov al, 2
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC minutes, in BCD
call bcd_to_bin ; eax now has minutes in binary
test al, al
jz rtc_post_hours
rtc_pos_min_loop: ; 18206507*60*0x100/1000000 = 0x44463 (279651.94752)
add cx, 0x4463
adc dx, 0x0004
dec al
jnz rtc_pos_min_loop
;; get RTC hours
rtc_post_hours:
mov al, 4
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC hours, in BCD
call bcd_to_bin ; eax now has hours in binary
test al, al
jz rtc_pos_shift
rtc_pos_hour_loop: ; 18206507*3600*0x100/1000000 = 0x100076C (16779116.8512)
add cx, 0x076C
adc dx, 0x0100
dec al
jnz rtc_pos_hour_loop
rtc_pos_shift:
mov cl, ch
mov ch, dl
mov dl, dh
xor dh, dh
mov ds:[46Ch], cx ; timer tick count
mov ds:[46Ch+2], dx ; timer tick count
mov ds:[470h], dh ; rollover flag
else
.386
;; get RTC seconds
xor eax, eax
mov al, 0
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC seconds, in BCD
call bcd_to_bin ; eax now has seconds in binary
mov edx, 18206507
mul edx
mov ebx, 1000000
xor edx, edx
div ebx
mov ecx, eax ; total ticks in ecx
;; get RTC minutes
xor eax, eax
mov al, 2
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC minutes, in BCD
call bcd_to_bin ; eax now has minutes in binary
mov edx, 10923904
mul edx
mov ebx, 10000
xor edx, edx
div ebx
add ecx, eax ; add to total ticks
;; get RTC hours
xor eax, eax
mov al, 4
out CMOS_ADDR, al
in al, CMOS_DATA ; RTC hours, in BCD
call bcd_to_bin ; eax now has hours in binary
mov edx, 65543427
mul edx
mov ebx, 1000
xor edx, edx
div ebx
add ecx, eax ; add to total ticks
mov ds:[46Ch], ecx ; timer tick count
xor al, al ; TODO: redundant?
mov ds:[470h], al ; rollover flag
.286
endif
ret
rtc_post endp
;; --------------------------------------------------------
;; INT 0Eh handler - Diskette IRQ 6 ISR
;; --------------------------------------------------------
BIOSORG 0EF57h, 0EF55h
int0e_handler:
push ax
push dx
mov dx, 3F4h
in al, dx
and al, 0C0h
cmp al, 0C0h
je int0e_normal
mov dx, 3F5h
mov al, 08h ; sense interrupt
out dx, al
int0e_loop1:
mov dx, 3F4h ; TODO: move out of the loop?
in al, dx
and al, 0C0h
cmp al, 0C0h
jne int0e_loop1
int0e_loop2:
mov dx, 3F5h ; TODO: inc/dec dx instead
in al, dx
mov dx, 3F4h
in al, dx
and al, 0C0h
cmp al, 0C0h
je int0e_loop2
int0e_normal:
push ds
xor ax, ax
mov ds, ax
call eoi_master_pic
; indicate that an interrupt occurred
or byte ptr ds:[43Eh], 80h
pop ds
pop dx
pop ax
iret
;; --------------------------------------------------------
;; Diskette Parameter Table
;; --------------------------------------------------------
BIOSORG 0EFC7h, 0EFC5h
_diskette_param_table:
db 0AFh
db 2 ; HLT=1, DMA mode
db 025h
db 2
db 18 ; SPT (good for 1.44MB media)
db 01Bh
db 0FFh
db 06Ch
db 0F6h ; format filler
db 15
db 8
;; --------------------------------------------------------
;; INT 17h handler - Printer service
;; --------------------------------------------------------
BIOSORG_CHECK 0EFD2h ; fixed WRT preceding code
jmp int17_handler ; NT floppy boot workaround
; see @bugref{6481}
int17_handler:
push ds
push es
DO_pusha
C_SETUP
call _int17_function
DO_popa
pop es
pop ds
iret
;; Protected mode IDT descriptor
;;
;; The limit is 0 to cause a shutdown if an exception occurs
;; in protected mode. TODO: Is that what we really want?
;;
;; Set base to F0000 to correspond to beginning of BIOS,
;; in case an IDT is defined later.
_pmode_IDT:
dw 0 ; limit 15:0
dw 0 ; base 15:0
dw 0Fh ; base 23:16
;; Real mode IDT descriptor
;;
;; Set to typical real-mode values.
;; base = 000000
;; limit = 03ff
_rmode_IDT:
dw 3FFh ; limit 15:00
dw 0 ; base 15:00
dw 0 ; base 23:16
;;
;; INT 1Ch
;;
;; TODO: Why does this need a special handler?
int1c_handler: ;; user timer tick
iret
;; --------------------------------------------------------
;; INT 10h functions 0-Fh entry point
;; --------------------------------------------------------
BIOSORG 0F045h, 0F043h
i10f0f_entry:
iret
;; --------------------------------------------------------
;; INT 10h handler - MDA/CGA video
;; --------------------------------------------------------
BIOSORG 0F065h, 0F063h
int10_handler:
;; do nothing - assumes VGA
iret
;; --------------------------------------------------------
;; MDA/CGA Video Parameter Table (INT 1Dh)
;; --------------------------------------------------------
BIOSORG 0F0A4h, 0F0A2h
mdacga_vpt:
;;
;; INT 18h - boot failure
;;
int18_handler:
C_SETUP
call _int18_panic_msg
;; TODO: handle failure better?
sti
stay_here:
hlt
jmp stay_here
;;
;; INT 19h - boot service - relocated
;;
int19_relocated:
;; The C worker function returns the boot drive in bl and
;; the boot segment in ax. In case of failure, the boot
;; segment will be zero.
C_SETUP ; TODO: Here? Now?
push bp
mov bp, sp
;; 1st boot device
mov ax, 1
push ax
call _int19_function
inc sp
inc sp
test ax, ax ; if 0, try next device
jnz boot_setup
;; 2nd boot device
mov ax, 2
push ax
call _int19_function
inc sp
inc sp
test ax, ax ; if 0, try next device
jnz boot_setup
; 3rd boot device
mov ax, 3
push ax
call _int19_function
inc sp
inc sp
test ax, ax ; if 0, try next device
jnz boot_setup
; 4th boot device
mov ax, 4
push ax
call _int19_function
inc sp
inc sp
test ax, ax ; if 0, invoke INT 18h
jz int18_handler
boot_setup:
; TODO: the drive should be in dl already??
;; mov dl, bl ; tell guest OS what boot drive is
if VBOX_BIOS_CPU lt 80386
mov [bp], ax
DO_shl ax, 4
mov [bp+2], ax ; set ip
mov ax, [bp]
else
.386 ; NB: We're getting garbage into high eax bits
shl eax, 4 ; convert seg to ip
mov [bp+2], ax ; set ip
shr eax, 4 ; get cs back
.286
endif
and ax, BIOSSEG ; remove what went in ip
mov [bp+4], ax ; set cs
xor ax, ax
mov ds, ax
mov es, ax
mov [bp], ax ; TODO: what's this?!
mov ax, 0AA55h ; set ok flag ; TODO: and this?
pop bp ; TODO: why'd we just zero it??
iret ; beam me up scotty
;; PCI BIOS
include pcibios.inc
include pirq.inc
if 0 ; Sample VPD table
;; IBM style VPD (Vital Product Data) information. Most IBM systems
;; had a VPD table since about 1992, later the same information was
;; also reported through DMI.
align 16
db 0AAh, 055h, 'VPD'
db 48 ; VPD size
db 'RESERVE' ; reserved... for what?
db 'INET35WW ' ; BIOS build ID
db '5238NXU' ; system serial number
db 'J1Y3581338D' ; unique ID
db '8643MD0' ; IBM machine type
db 0 ; checksum (to be calculated)
endif
;; --------------------------------------------------------
;; INT 12h handler - Memory size
;; --------------------------------------------------------
BIOSORG 0F841h, 0F83Fh
int12_handler:
;; Don't touch - fixed size!
sti
push ds
mov ax, 40h
mov ds, ax
mov ax, ds:[13h]
pop ds
iret
;; --------------------------------------------------------
;; INT 11h handler - Equipment list service
;; --------------------------------------------------------
BIOSORG_CHECK 0F84Dh ; fixed wrt preceding code
int11_handler:
;; Don't touch - fixed size!
sti
push ds
mov ax, 40h
mov ds, ax
mov ax, ds:[10h]
pop ds
iret
;; --------------------------------------------------------
;; INT 15h handler - System services
;; --------------------------------------------------------
BIOSORG_CHECK 0F859h ; fixed wrt preceding code
int15_handler:
if VBOX_BIOS_CPU ge 80286
cmp ah, 87h
jne not_blkmove
;; INT 15h/87h has semi-public interface because software
;; may use CMOS shutdown status code 9 for its own purposes.
;; The stack layout has to match.
pusha
push es
push ds
C_SETUP
call _int15_blkmove
pop ds
pop es
popa
iret
not_blkmove:
endif
pushf
push ds
push es
C_SETUP
if VBOX_BIOS_CPU ge 80386
;; int15_function32 exists in 386+ BIOS only, but INT 15h is
;; not 386-specific
cmp ah, 0E8h
je int15_handler32
cmp ah, 0d0h
je int15_handler32
endif
DO_pusha
cmp ah, 53h ; APM function?
je apm_call
cmp ah, 0C2h ; PS/2 mouse function?
je int15_handler_mouse
call _int15_function
int15_handler_popa_ret:
DO_popa
if VBOX_BIOS_CPU ge 80386
int15_handler32_ret:
endif
pop es
pop ds
popf
jmp iret_modify_cf
apm_call:
call _apm_function
jmp int15_handler_popa_ret
int15_handler_mouse:
call _int15_function_mouse
jmp int15_handler_popa_ret
if VBOX_BIOS_CPU ge 80386
int15_handler32:
;; need to save/restore 32-bit registers
.386
pushad
call _int15_function32
popad
.286
jmp int15_handler32_ret
endif
;;
;; Perform an IRET but retain the current carry flag value
;;
iret_modify_cf:
jc carry_set
push bp
mov bp, sp
and byte ptr [bp + 6], 0FEh
or word ptr [bp + 6], 0200h
pop bp
iret
carry_set:
push bp
mov bp, sp
or word ptr [bp + 6], 0201h
pop bp
iret
;;
;; INT 74h handler - PS/2 mouse (IRQ 12)
;;
int74_handler proc
sti
DO_pusha
push es
push ds
xor ax, ax
push ax ; placeholder for status
push ax ; placeholder for X
push ax ; placeholder for Y
push ax ; placeholder for Z
push ax ; placeholder for make_far_call bool
C_SETUP
call _int74_function
pop cx ; pop make_far_call flag
jcxz int74_done
;; make far call to EBDA:0022
if VBOX_BIOS_CPU ge 80186
push 0
else
xor ax, ax
push ax
endif
pop ds
push ds:[40Eh]
pop ds
call far ptr ds:[22h]
int74_done:
cli
call eoi_both_pics
add sp, 8 ; remove status, X, Y, Z
pop ds
pop es
DO_popa
iret
int74_handler endp
int76_handler proc
;; record completion in BIOS task complete flag
push ax
push ds
mov ax, 40h
mov ds, ax
mov byte ptr ds:[8Eh], 0FFh
call eoi_both_pics
pop ds
pop ax
iret
int76_handler endp
;;
;; IRQ 8 handler (RTC)
;;
int70_handler:
push es
push ds
DO_pusha
C_SETUP
call _int70_function
DO_popa
pop ds
pop es
iret
if VBOX_BIOS_CPU lt 80386
;
; We're tight on space down below in the int08_handler, so put
; the 16-bit rollover code here.
;
int08_maybe_rollover:
ja int08_rollover
cmp ax, 00B0h
jb int08_rollover_store
;; there has been a midnight rollover
int08_rollover:
xor dx, dx
xor ax, ax
inc byte ptr ds:[70h] ; increment rollover flag
int08_rollover_store:
jmp int08_store_ticks
endif
;; --------------------------------------------------------
;; 8x8 font (first 128 characters)
;; --------------------------------------------------------
BIOSORG 0FA6Eh, 0FA6Ch
include font8x8.inc
;; --------------------------------------------------------
;; INT 1Ah handler - Time of the day + PCI BIOS
;; --------------------------------------------------------
BIOSORG_CHECK 0FE6Eh ; fixed wrt preceding table
int1a_handler:
if VBOX_BIOS_CPU ge 80386
cmp ah, 0B1h
jne int1a_normal
push es
push ds
C_SETUP
.386
pushad
call _pci16_function
popad
.286
pop ds
pop es
iret
endif
int1a_normal:
push es
push ds
DO_pusha
C_SETUP
int1a_callfunction:
call _int1a_function
DO_popa
pop ds
pop es
iret
;; --------------------------------------------------------
;; Timer tick - IRQ 0 handler
;; --------------------------------------------------------
BIOSORG 0FEA5h, 0FEA3h
int08_handler:
if VBOX_BIOS_CPU ge 80386
.386
sti
push eax
else
sti
push ax
endif
push ds
push dx
mov ax, 40h
mov ds, ax
if VBOX_BIOS_CPU ge 80386
mov eax, ds:[6Ch] ; get ticks dword
inc eax
else
mov ax, ds:[6Ch] ; get ticks dword
mov dx, ds:[6Ch+2]
inc ax ; inc+jz+inc saves two bytes over add+adc.
jnz int08_compare
inc dx
int08_compare:
endif
;; compare eax to one day's worth of ticks (at 18.2 Hz)
if VBOX_BIOS_CPU ge 80386
cmp eax, 1800B0h
jb int08_store_ticks
else
cmp dx, 18h
jb int08_store_ticks
jmp int08_maybe_rollover
endif
if VBOX_BIOS_CPU ge 80386
;; there has been a midnight rollover
xor eax, eax
inc byte ptr ds:[70h] ; increment rollover flag
int08_store_ticks:
mov ds:[6Ch], eax
else
int08_store_ticks:
mov ds:[6Ch], ax
mov ds:[6Ch+2], dx
endif
;; time to turn off floppy drive motor(s)?
mov al, ds:[40h]
or al, al
jz int08_floppy_off
dec al
mov ds:[40h], al
jnz int08_floppy_off
;; turn motor(s) off
mov dx, 03F2h
in al, dx
and al, 0CFh
out dx, al
int08_floppy_off:
int 1Ch ; call the user timer handler
cli
call eoi_master_pic
pop dx
pop ds
if VBOX_BIOS_CPU ge 80386
pop eax
.286
else
pop ax
endif
iret
;; --------------------------------------------------------
;; Initial interrupt vector offsets for POST
;; --------------------------------------------------------
BIOSORG 0FEF3h, 0FEF1h
vector_table:
;; --------------------------------------------------------
;; BIOS copyright string
;; --------------------------------------------------------
BIOSORG 0FF00h, 0FEFEh
bios_string:
db BIOS_COPYRIGHT
;; --------------------------------------------------------
;; IRET - default interrupt handler
;; --------------------------------------------------------
BIOSORG 0FF53h, 0FF51h
dummy_iret:
iret
;; --------------------------------------------------------
;; INT 05h - Print Screen service
;; --------------------------------------------------------
BIOSORG_CHECK 0FF54h ; fixed wrt preceding
int05_handler:
;; Not implemented
iret
include smidmi.inc
;; --------------------------------------------------------
;; Processor reset entry point
;; --------------------------------------------------------
BIOSORG 0FFF0h, 0FFEEh
cpu_reset:
;; This is where the CPU starts executing after a reset
jmp far ptr post
;; BIOS build date
db BIOS_BUILD_DATE
db 0 ; null terminator
;; System model ID
db SYS_MODEL_ID
;; Checksum byte
db 0FFh
BIOSSEG ends
end
|