pcibios.inc revision 94fde0b66aced35ee31b2218ab4371f2a48888c1
;;
;; Copyright (C) 2006-2011 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
;;
;;
include pcicfg.inc
if BX_PCIBIOS
extrn pcibios_protected:near ; in a 32-bit segment
ifdef DEBUG
; Publics for easier debugging and disassembly
public pcibios_real
public pci_present
public pci_real_f02
public pci_real_devloop
public pci_real_nextdev
public pci_real_f03
public pci_real_devloop2
public pci_real_nextdev2
public pci_real_ok
public pci_real_fail
public pci_real_select_reg
public pcibios_init_iomem_bases
public pci_init_io_loop1
public pci_init_io_loop2
public init_io_base
public next_pci_base
public enable_iomem_space
public next_pci_dev
public pcibios_init_set_elcr
public is_master_pic
public pcibios_init_irqs
public pci_init_irq_loop1
public pci_init_irq_loop2
public pci_test_int_pin
public pirq_found
public next_pci_func
public next_pir_entry
public pci_init_end
endif
.386
pcibios_real:
push eax
push dx
ifdef PCI_FIXED_HOST_BRIDGE_1
mov eax, 80000000h
mov dx, PCI_CFG1
out dx, eax
mov dx, PCI_CFG2
in eax, dx
cmp eax, PCI_FIXED_HOST_BRIDGE_1
je pci_present
endif
ifdef PCI_FIXED_HOST_BRIDGE_2
; 18h << 11
mov eax, 8000c000h
mov dx, PCI_CFG1
out dx, eax
mov dx, PCI_CFG2
in eax, dx
cmp eax, PCI_FIXED_HOST_BRIDGE_2
je pci_present
; 19h << 11
mov eax, 8000c800h
mov dx, PCI_CFG1
out dx, eax
mov dx, PCI_CFG2
in eax, dx
cmp eax, PCI_FIXED_HOST_BRIDGE_2
je pci_present
endif
pop dx
pop eax
mov ah, 0FFh
stc
ret
pci_present:
pop dx
pop eax
cmp al, 1 ; installation check
jne pci_real_f02
mov ax, 0001h
mov bx, 0210h
mov cx, 0
mov edx, ' ICP' ; #0x20494350 "PCI "
;; @todo!
if 0
mov edi, 0f0000h
mov di, pcibios_protected
else
mov edi, pcibios_protected
endif
clc
ret
pci_real_f02: ;; find pci device
push esi
push edi
push edx
cmp al, 2
jne pci_real_f03
shl ecx, 16
mov cx, dx
xor ebx, ebx
mov di, 0
pci_real_devloop:
call pci_real_select_reg
mov dx, PCI_CFG2
in eax, dx
cmp eax, ecx
jne pci_real_nextdev
cmp si, 0
je pci_real_ok
dec si
pci_real_nextdev:
inc ebx
cmp ebx, MAX_BUSDEVFN
jne pci_real_devloop
mov dx, cx
shr ecx, 16
mov ax, 8602h
jmp pci_real_fail
pci_real_f03: ;; find class code
cmp al, 3
jne pci_real_f08
xor ebx, ebx
mov di, 8
pci_real_devloop2:
call pci_real_select_reg
mov dx, PCI_CFG2
in eax, dx
shr eax, 8
cmp eax, ecx
jne pci_real_nextdev2
cmp si, 0
je pci_real_ok
dec si
pci_real_nextdev2:
inc ebx
cmp ebx, MAX_BUSDEVFN
jne pci_real_devloop2
mov ax, 8603h
jmp pci_real_fail
pci_real_f08: ;; read configuration byte
cmp al, 8
jne pci_real_f09
call pci_real_select_reg
push dx
mov dx, di
and dx, 3
add dx, PCI_CFG2
in al, dx
pop dx
mov cl, al
jmp pci_real_ok
pci_real_f09: ;; read configuration word
cmp al, 9
jne pci_real_f0a
call pci_real_select_reg
push dx
mov dx, di
and dx, 2
add dx, PCI_CFG2
in ax, dx
pop dx
mov cx, ax
jmp pci_real_ok
pci_real_f0a: ;; read configuration dword
cmp al, 0Ah
jne pci_real_f0b
call pci_real_select_reg
push dx
mov dx, PCI_CFG2
in eax, dx
pop dx
mov ecx, eax
jmp pci_real_ok
pci_real_f0b: ;; write configuration byte
cmp al, 0Bh
jne pci_real_f0c
call pci_real_select_reg
push dx
mov dx, di
and dx, 3
add dx, PCI_CFG2
mov al, cl
out dx, al
pop dx
jmp pci_real_ok
pci_real_f0c: ;; write configuration word
cmp al, 0Ch
jne pci_real_f0d
call pci_real_select_reg
push dx
mov dx, di
and dx, 2
add dx, PCI_CFG2
mov ax, cx
out dx, ax
pop dx
jmp pci_real_ok
pci_real_f0d: ;; write configuration dword
cmp al, 0Dh
jne pci_real_f0e
call pci_real_select_reg
push dx
mov dx, PCI_CFG2
mov eax, ecx
out dx, eax
pop dx
jmp pci_real_ok
pci_real_f0e: ;; get irq routing options
cmp al, 0Eh
jne pci_real_unknown
cmp word ptr es:[di], pci_routing_table_structure_end - pci_routing_table_structure_start
jb pci_real_too_small
mov word ptr es:[di], pci_routing_table_structure_end - pci_routing_table_structure_start
pushf
push ds
push es
push cx
push si
push di
cld
mov si, pci_routing_table_structure_start
push cs
pop ds
mov cx, es:[di+2]
mov es, es:[di+4]
mov di, cx
mov cx, pci_routing_table_structure_end - pci_routing_table_structure_start
rep movsb
pop di
pop si
pop cx
pop es
pop ds
popf
mov bx, (1 shl 9) or (1 shl 11) ; #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used
jmp pci_real_ok
pci_real_too_small:
mov word ptr es:[di], pci_routing_table_structure_end - pci_routing_table_structure_start
mov ah, 89h
jmp pci_real_fail
pci_real_unknown:
mov ah, 81h
pci_real_fail:
pop edx
pop edi
pop esi
stc
ret
pci_real_ok:
xor ah, ah
pop edx
pop edi
pop esi
clc
ret
;; prepare from reading the PCI config space; on input:
;; bx = bus/dev/fn
;; di = offset into config space header
;; destroys eax and may modify di
pci_real_select_reg:
push dx
mov eax, 800000h
mov ax, bx
shl eax, 8
and di, 0FFh
or ax, di
and al, 0FCh
mov dx, PCI_CFG1
out dx, eax
pop dx
ret
if not BX_ROMBIOS32
pci_irq_list:
db 11, 10, 9, 5;
pcibios_init_sel_reg:
push eax
mov eax, 800000h
mov ax, bx
shl eax, 8
and dl, 0FCh
or al, dl
mov dx, PCI_CFG1
out dx, eax
pop eax
ret
pcibios_init_iomem_bases:
push bp
mov bp, sp
mov eax, 0E0000000h ; base for memory init
push eax
mov ax, 0D000h ; base for i/o init
push ax
mov ax, 010h ; start at base address #0
push ax
mov bx, 8
pci_init_io_loop1:
mov dl, 0
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in ax, dx
cmp ax, 0FFFFh
jz next_pci_dev
ifndef VBOX ; This currently breaks restoring a previously saved state. */
mov dl, 4 ; disable i/o and memory space access
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in al, dx
and al, 0FCh
out dx, al
pci_init_io_loop2:
mov dl, [bp-8]
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in eax, dx
test al, 1
jnz init_io_base
mov ecx, eax
mov eax, 0FFFFFFFFh
out dx, eax
in eax, dx
cmp eax, ecx
je next_pci_base
xor eax, 0FFFFFFFFh
mov ecx, eax
mov eax, [bp-4]
out dx, eax
add eax, ecx ; calculate next free mem base
add eax, 01000000h
and eax, 0FF000000h
mov [bp-4], eax
jmp next_pci_base
init_io_base:
mov cx, ax
mov ax, 0FFFFh
out dx, eax
in eax, dx
cmp ax, cx
je next_pci_base
xor ax, 0FFFEh
mov cx, ax
mov ax, [bp-6]
out dx, eax
add ax, cx ; calculate next free i/o base
add ax, 00100h
and ax, 0FF00h
mov [bp-6], ax
next_pci_base:
mov al, [bp-8]
add al, 4
cmp al, 28h
je enable_iomem_space
mov byte ptr[bp-8], al
jmp pci_init_io_loop2
endif ; !VBOX
enable_iomem_space:
mov dl, 4 ;; enable i/o and memory space access if available
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in al, dx
or al, 7
out dx, al
ifdef VBOX
mov dl, 0 ; check if PCI device is AMD PCNet
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in eax, dx
cmp eax, 020001022h
jne next_pci_dev
mov dl, 10h ; get I/O address
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in ax, dx
and ax, 0FFFCh
mov cx, ax
mov dx, cx
add dx, 14h ; reset register if PCNet is in word I/O mode
in ax, dx ; reset is performed by reading the reset register
mov dx, cx
add dx, 18h ; reset register if PCNet is in word I/O mode
in eax, dx ; reset is performed by reading the reset register
endif ; VBOX
next_pci_dev:
mov byte ptr[bp-8], 10h
inc bx
cmp bx, 0100h
jne pci_init_io_loop1
mov sp, bp
pop bp
ret
pcibios_init_set_elcr:
push ax
push cx
mov dx, 04D0h
test al, 8
jz is_master_pic
inc dx
and al, 7
is_master_pic:
mov cl, al
mov bl, 1
shl bl, cl
in al, dx
or al, bl
out dx, al
pop cx
pop ax
ret
pcibios_init_irqs:
push ds
push bp
mov ax, 0F000h
mov ds, ax
mov dx, 04D0h ;; reset ELCR1 + ELCR2
mov al, 0
out dx, al
inc dx
out dx, al
mov si, pci_routing_table_structure
mov bh, [si+8]
mov bl, [si+9]
mov dl, 0
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in eax, dx
cmp eax, [si+12] ;; check irq router
jne pci_init_end
mov dl, [si+34]
call pcibios_init_sel_reg
push bx ;; save irq router bus + devfunc
mov dx, PCI_CFG2
mov ax, 8080h
out dx, ax ;; reset PIRQ route control
add dx, 2
out dx, ax
mov ax, [si+6]
sub ax, 20h
shr ax, 4
mov cx, ax
add si, 20h ;; set pointer to 1st entry
mov bp, sp
mov ax, pci_irq_list
push ax
xor ax, ax
push ax
pci_init_irq_loop1:
mov bh, [si]
mov bl, [si+1]
pci_init_irq_loop2:
mov dl, 0
call pcibios_init_sel_reg
mov dx, PCI_CFG2
in ax, dx
cmp ax, 0FFFFh
jnz pci_test_int_pin
test bl, 7
jz next_pir_entry
jmp next_pci_func
pci_test_int_pin:
mov dl, 3Ch
call pcibios_init_sel_reg
mov dx, PCI_CFG2 + 1 ; TODO: was #0x0cfd - is that right?
in al, dx
and al, 7
jz next_pci_func
dec al ;; determine pirq reg
mov dl, 3
mul dl
add al, 2
xor ah, ah
mov bx, ax
mov al, [si+bx]
mov dl, al
mov bx, [bp]
call pcibios_init_sel_reg
mov dx, PCI_CFG2
and al, 3
add dl, al
in al, dx
cmp al, 80h
jb pirq_found
mov bx, [bp-2] ;; pci irq list pointer
mov al, [bx]
out dx, al
inc bx
mov [bp-2], bx
call pcibios_init_set_elcr
pirq_found:
mov bh, [si]
mov bl, [si+1]
add bl, [bp-3] ;; pci function number
mov dl, 3Ch
call pcibios_init_sel_reg
mov dx, PCI_CFG2
out dx, al
next_pci_func:
inc byte ptr[bp-3]
inc bl
test bl, 7
jnz pci_init_irq_loop2
next_pir_entry:
add si, 10h
mov byte ptr[bp-3], 0
loop pci_init_irq_loop1
mov sp, bp
pop bx
pci_init_end:
pop bp
pop ds
ret
.286
endif ; !BX_ROMBIOS32
endif ; BX_PCIBIOS