summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/PC/BIOS/orgs.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/PC/BIOS/orgs.asm')
-rw-r--r--src/VBox/Devices/PC/BIOS/orgs.asm2069
1 files changed, 2069 insertions, 0 deletions
diff --git a/src/VBox/Devices/PC/BIOS/orgs.asm b/src/VBox/Devices/PC/BIOS/orgs.asm
new file mode 100644
index 00000000..1706b71d
--- /dev/null
+++ b/src/VBox/Devices/PC/BIOS/orgs.asm
@@ -0,0 +1,2069 @@
+; $Id: orgs.asm $
+;; @file
+; ???
+;
+
+;
+; Copyright (C) 2006-2019 Oracle Corporation
+;
+; This file is part of VirtualBox Open Source Edition (OSE), as
+; available from http://www.virtualbox.org. This file is free software;
+; you can redistribute it and/or modify it under the terms of the GNU
+; General Public License (GPL) as published by the Free Software
+; Foundation, in version 2 as it comes in the "COPYING" file of the
+; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+; --------------------------------------------------------------------
+;
+; 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_SEG equ 09FC0h ; starts at 639K
+EBDA_SIZE equ 1 ; 1K
+BASE_MEM_IN_K equ (640 - EBDA_SIZE)
+
+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
+else
+SYS_MODEL_ID equ 0FBh ; PC/XT
+endif
+SYS_SUBMODEL_ID equ 0
+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 ax, BASE_MEM_IN_K
+ 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
+ ;; TODO: What's the point? The BDA is zeroed already?!
+ mov ds:[417h], al ; keyboard shift flags, set 1
+ mov ds:[418h], al ; keyboard shift flags, set 2
+ mov ds:[419h], al ; keyboard Alt-numpad work area
+ mov ds:[471h], al ; keyboard Ctrl-Break flag
+ mov ds:[497h], al ; keyboard status flags 4
+ 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 Parameter Table
+;; --------------------------------------------------------
+ BIOSORG_CHECK 0E401h ; fixed wrt preceding
+
+rom_fdpt:
+
+;; --------------------------------------------------------
+;; 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
+
+ mov ax, EBDA_SEG
+ mov ds, ax
+ mov byte ptr ds:[0], EBDA_SIZE
+ ;; store EBDA seg in 40:0E
+ xor ax, ax
+ mov ds, ax
+ mov word ptr ds:[40Eh], EBDA_SEG
+ 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?
+ hlt
+ iret
+
+;;
+;; INT 19h - boot service - relocated
+;;
+int19_relocated:
+; If an already booted OS calls int 0x19 to reboot, it is not sufficient
+; just to try booting from the configured drives. All BIOS variables and
+; interrupt vectors need to be reset, otherwise strange things may happen.
+; The approach used is faking a warm reboot (which just skips showing the
+; logo), which is a bit more than what we need, but hey, it's fast.
+ mov bp, sp
+ mov ax, [bp+2] ; TODO: redundant? address via sp?
+ cmp ax, BIOSSEG ; check caller's segment
+ jz bios_initiated_boot
+
+ xor ax, ax
+ mov ds, ax
+ mov ax, 1234h
+ mov ds:[472], ax
+ jmp post
+
+bios_initiated_boot:
+ ;; 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
+
+
+;; --------------------------------------------------------
+;; 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 ; padding
+ ;; System model ID
+ db SYS_MODEL_ID
+ ;; Checksum byte
+ db 0FFh
+
+
+BIOSSEG ends
+
+ end
+