|
|
|
/*
|
|
|
|
* (C) Copyright 2002
|
|
|
|
* Daniel Engström, Omicron Ceti AB, daniel@omicron.se
|
|
|
|
*
|
|
|
|
* See file CREDITS for list of people who contributed to this
|
|
|
|
* project.
|
|
|
|
*
|
|
|
|
* 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; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* x86 realmode assembly implementation of a PCI BIOS
|
|
|
|
* for platforms that use one PCI hose and configuration
|
|
|
|
* access type 1. (The common case for low-end PC's)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "bios.h"
|
|
|
|
|
|
|
|
#define PCI_BIOS_DEBUG
|
|
|
|
|
|
|
|
.section .bios, "ax"
|
|
|
|
.code16
|
|
|
|
.globl realmode_pci_bios_call_entry
|
|
|
|
.hidden realmode_pci_bios_call_entry
|
|
|
|
.type realmode_pci_bios_call_entry, @function
|
|
|
|
realmode_pci_bios_call_entry:
|
|
|
|
MAKE_BIOS_STACK
|
|
|
|
call realmode_pci_bios
|
|
|
|
RESTORE_CALLERS_STACK
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
.globl realmode_pci_bios
|
|
|
|
realmode_pci_bios:
|
|
|
|
gs movw OFFS_AX(%bp), %ax
|
|
|
|
cmpb $1, %al
|
|
|
|
je pci_bios_present
|
|
|
|
cmpb $2, %al
|
|
|
|
je pci_bios_find_device
|
|
|
|
cmpb $3, %al
|
|
|
|
je pci_bios_find_class
|
|
|
|
cmpb $6, %al
|
|
|
|
je pci_bios_generate_special_cycle
|
|
|
|
cmpb $8, %al
|
|
|
|
je pci_bios_read_cfg_byte
|
|
|
|
cmpb $9, %al
|
|
|
|
je pci_bios_read_cfg_word
|
|
|
|
cmpb $10, %al
|
|
|
|
je pci_bios_read_cfg_dword
|
|
|
|
cmpb $11, %al
|
|
|
|
je pci_bios_write_cfg_byte
|
|
|
|
cmpb $12, %al
|
|
|
|
je pci_bios_write_cfg_word
|
|
|
|
cmpb $13, %al
|
|
|
|
je pci_bios_write_cfg_dword
|
|
|
|
cmpb $14, %al
|
|
|
|
je pci_bios_get_irq_routing
|
|
|
|
cmpb $15, %al
|
|
|
|
je pci_bios_set_irq
|
|
|
|
jmp unknown_function
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_present:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_present
|
|
|
|
#endif
|
|
|
|
movl $0x20494350, %eax
|
|
|
|
gs movl %eax, OFFS_EDX(%bp)
|
|
|
|
|
|
|
|
/* We support cfg type 1 version 2.10 */
|
|
|
|
movb $0x01, %al
|
|
|
|
gs movb %al, OFFS_AL(%bp)
|
|
|
|
movw $0x0210, %ax
|
|
|
|
gs movw %ax, OFFS_BX(%bp)
|
|
|
|
|
|
|
|
/* last bus number */
|
|
|
|
cs movb pci_last_bus, %al
|
|
|
|
gs movb %al, OFFS_CL(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
/* device 0-31, function 0-7 */
|
|
|
|
pci_bios_find_device:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_find_device
|
|
|
|
#endif
|
|
|
|
gs movw OFFS_CX(%bp), %di
|
|
|
|
shll $16, %edi
|
|
|
|
gs movw OFFS_DX(%bp), %di
|
|
|
|
/* edi now holds device in upper 16 bits and vendor in lower 16 bits */
|
|
|
|
|
|
|
|
gs movw OFFS_SI(%bp), %si
|
|
|
|
|
|
|
|
/* start at bus 0 dev 0 function 0 */
|
|
|
|
xorw %bx, %bx
|
|
|
|
pfd_loop:
|
|
|
|
/* dword 0 is vendor/device */
|
|
|
|
xorw %ax, %ax
|
|
|
|
call __pci_bios_select_register
|
|
|
|
movw $0xcfc, %dx
|
|
|
|
inl %dx, %eax
|
|
|
|
|
|
|
|
/* our device ? */
|
|
|
|
cmpl %edi, %eax
|
|
|
|
je pfd_found_one
|
|
|
|
pfd_next_dev:
|
|
|
|
/* check for multi function devices */
|
|
|
|
movw %bx, %ax
|
|
|
|
andw $3, %ax
|
|
|
|
jnz pfd_function_not_zero
|
|
|
|
movw $0x000c, %ax
|
|
|
|
call __pci_bios_select_register
|
|
|
|
movw $0xcfe, %dx
|
|
|
|
inb %dx, %al
|
|
|
|
andb $0x80, %al
|
|
|
|
jz pfd_not_multi_function
|
|
|
|
pfd_function_not_zero:
|
|
|
|
/* next function, overflows in to device number, then bus number */
|
|
|
|
incw %bx
|
|
|
|
jmp pfd_check_bus
|
|
|
|
|
|
|
|
pfd_not_multi_function:
|
|
|
|
/* remove function bits */
|
|
|
|
andw $0xfff8, %bx
|
|
|
|
|
|
|
|
/* next device, overflows in to bus number */
|
|
|
|
addw $0x0008, %bx
|
|
|
|
pfd_check_bus:
|
|
|
|
cs movb pci_last_bus, %ah
|
|
|
|
cmpb %ah, %bh
|
|
|
|
ja pfd_not_found
|
|
|
|
jmp pfd_loop
|
|
|
|
pfd_found_one:
|
|
|
|
decw %si
|
|
|
|
js pfd_done
|
|
|
|
jmp pfd_next_dev
|
|
|
|
|
|
|
|
pfd_done:
|
|
|
|
gs movw %bx, OFFS_BX(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
pfd_not_found:
|
|
|
|
/* device not found */
|
|
|
|
movb $0x86, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_find_class:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_find_class
|
|
|
|
#endif
|
|
|
|
gs movl OFFS_ECX(%bp), %edi
|
|
|
|
|
|
|
|
/* edi now holds class-code in lower 24 bits */
|
|
|
|
andl $0x00ffffff, %edi
|
|
|
|
gs movw OFFS_SI(%bp), %si
|
|
|
|
|
|
|
|
/* start at bus 0 dev 0 function 0 */
|
|
|
|
xorw %bx, %bx
|
|
|
|
pfc_loop:
|
|
|
|
/* dword 8 is class-code high 24bits */
|
|
|
|
movw $8, %ax
|
|
|
|
call __pci_bios_select_register
|
|
|
|
movw $0xcfc, %dx
|
|
|
|
inl %dx, %eax
|
|
|
|
shrl $8, %eax
|
|
|
|
andl $0x00ffffff, %eax
|
|
|
|
|
|
|
|
/* our device ? */
|
|
|
|
cmpl %edi, %eax
|
|
|
|
je pfc_found_one
|
|
|
|
pfc_next_dev:
|
|
|
|
/* check for multi function devices */
|
|
|
|
andw $3, %bx
|
|
|
|
jnz pfc_function_not_zero
|
|
|
|
movw $0x000c, %ax
|
|
|
|
call __pci_bios_select_register
|
|
|
|
movw $0xcfe, %dx
|
|
|
|
inb %dx, %al
|
|
|
|
andb $0x80, %al
|
|
|
|
jz pfc_not_multi_function
|
|
|
|
pfc_function_not_zero:
|
|
|
|
/* next function, overflows in to device number, then bus number */
|
|
|
|
incw %bx
|
|
|
|
jmp pfc_check_bus
|
|
|
|
|
|
|
|
pfc_not_multi_function:
|
|
|
|
/* remove function bits */
|
|
|
|
andw $0xfff8, %bx
|
|
|
|
|
|
|
|
/* next device, overflows in to bus number */
|
|
|
|
addw $0x0008, %bx
|
|
|
|
pfc_check_bus:
|
|
|
|
cs movb pci_last_bus, %ah
|
|
|
|
cmpb %ah, %bh
|
|
|
|
ja pfc_not_found
|
|
|
|
jmp pfc_loop
|
|
|
|
pfc_found_one:
|
|
|
|
decw %si
|
|
|
|
js pfc_done
|
|
|
|
jmp pfc_next_dev
|
|
|
|
|
|
|
|
pfc_done:
|
|
|
|
gs movw %bx, OFFS_BX(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
pfc_not_found:
|
|
|
|
/* device not found */
|
|
|
|
movb $0x86, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_generate_special_cycle:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_generate_special_cycle
|
|
|
|
#endif
|
|
|
|
/* function not supported */
|
|
|
|
movb $0x81, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_read_cfg_byte:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_read_cfg_byte
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
gs movw OFFS_DI(%bp), %dx
|
|
|
|
andw $3, %dx
|
|
|
|
addw $0xcfc, %dx
|
|
|
|
inb %dx, %al
|
|
|
|
gs movb %al, OFFS_CL(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_read_cfg_word:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_read_cfg_word
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
gs movw OFFS_DI(%bp), %dx
|
|
|
|
andw $2, %dx
|
|
|
|
addw $0xcfc, %dx
|
|
|
|
inw %dx, %ax
|
|
|
|
gs movw %ax, OFFS_CX(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_read_cfg_dword:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_read_cfg_dword
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
movw $0xcfc, %dx
|
|
|
|
inl %dx, %eax
|
|
|
|
gs movl %eax, OFFS_ECX(%bp)
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_write_cfg_byte:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_write_cfg_byte
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
gs movw OFFS_DI(%bp), %dx
|
|
|
|
gs movb OFFS_CL(%bp), %al
|
|
|
|
andw $3, %dx
|
|
|
|
addw $0xcfc, %dx
|
|
|
|
outb %al, %dx
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_write_cfg_word:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_write_cfg_word
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
gs movw OFFS_DI(%bp), %dx
|
|
|
|
gs movw OFFS_CX(%bp), %ax
|
|
|
|
andw $2, %dx
|
|
|
|
addw $0xcfc, %dx
|
|
|
|
outw %ax, %dx
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_write_cfg_dword:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_write_cfg_dword
|
|
|
|
#endif
|
|
|
|
call pci_bios_select_register
|
|
|
|
gs movl OFFS_ECX(%bp), %eax
|
|
|
|
movw $0xcfc, %dx
|
|
|
|
outl %eax, %dx
|
|
|
|
jmp clear_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_get_irq_routing:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_get_irq_routing
|
|
|
|
#endif
|
|
|
|
/* function not supported */
|
|
|
|
movb $0x81, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_set_irq:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_set_irq
|
|
|
|
#endif
|
|
|
|
/* function not supported */
|
|
|
|
movb $0x81, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
unknown_function:
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
cs incl num_pci_bios_unknown_function
|
|
|
|
#endif
|
|
|
|
/* function not supported */
|
|
|
|
movb $0x81, %ah
|
|
|
|
jmp set_carry
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
pci_bios_select_register:
|
|
|
|
gs movw OFFS_BX(%bp), %bx
|
|
|
|
gs movw OFFS_DI(%bp), %ax
|
|
|
|
/* destroys eax, dx */
|
|
|
|
__pci_bios_select_register:
|
|
|
|
/* BX holds device id, AX holds register index */
|
|
|
|
pushl %ebx
|
|
|
|
andl $0xfc, %eax
|
|
|
|
andl $0xffff, %ebx
|
|
|
|
shll $8, %ebx
|
|
|
|
orl %ebx, %eax
|
|
|
|
orl $0x80000000, %eax
|
|
|
|
movw $0xcf8, %dx
|
|
|
|
outl %eax, %dx
|
|
|
|
popl %ebx
|
|
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
clear_carry:
|
|
|
|
gs movw OFFS_FLAGS(%bp), %ax
|
|
|
|
|
|
|
|
/* clear carry -- function succeeded */
|
|
|
|
andw $0xfffe, %ax
|
|
|
|
gs movw %ax, OFFS_FLAGS(%bp)
|
|
|
|
xorw %ax, %ax
|
|
|
|
gs movb %ah, OFFS_AH(%bp)
|
|
|
|
ret
|
|
|
|
|
|
|
|
set_carry:
|
|
|
|
gs movb %ah, OFFS_AH(%bp)
|
|
|
|
gs movw OFFS_FLAGS(%bp), %ax
|
|
|
|
|
|
|
|
/* return carry -- function not supported */
|
|
|
|
orw $1, %ax
|
|
|
|
gs movw %ax, OFFS_FLAGS(%bp)
|
|
|
|
movw $-1, %ax
|
|
|
|
ret
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
.globl pci_last_bus
|
|
|
|
pci_last_bus:
|
|
|
|
.byte 0
|
|
|
|
|
|
|
|
#ifdef PCI_BIOS_DEBUG
|
|
|
|
.globl num_pci_bios_present
|
|
|
|
num_pci_bios_present:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_find_device
|
|
|
|
num_pci_bios_find_device:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_find_class
|
|
|
|
num_pci_bios_find_class:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_generate_special_cycle
|
|
|
|
num_pci_bios_generate_special_cycle:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_read_cfg_byte
|
|
|
|
num_pci_bios_read_cfg_byte:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_read_cfg_word
|
|
|
|
num_pci_bios_read_cfg_word:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_read_cfg_dword
|
|
|
|
num_pci_bios_read_cfg_dword:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_write_cfg_byte
|
|
|
|
num_pci_bios_write_cfg_byte:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_write_cfg_word
|
|
|
|
num_pci_bios_write_cfg_word:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_write_cfg_dword
|
|
|
|
num_pci_bios_write_cfg_dword:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_get_irq_routing
|
|
|
|
num_pci_bios_get_irq_routing:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_set_irq
|
|
|
|
num_pci_bios_set_irq:
|
|
|
|
.long 0
|
|
|
|
|
|
|
|
.globl num_pci_bios_unknown_function
|
|
|
|
num_pci_bios_unknown_function:
|
|
|
|
.long 0
|
|
|
|
#endif
|