⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcipnp.8

📁 tiny bios--了解BIOS非常好的资料
💻 8
📖 第 1 页 / 共 2 页
字号:
	;
	; PCI plug & play
	;
	; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
	; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
	;

	; pd 000830 add PCI_NORST2 option -> don't touch base register
	;           for second motherboard device (e.g. USB)
	; pd 991115 fix PCI I/O allocation: some devices (e.g. ESS Tech)
	;           have 16 bit base registers.
	; pd 990329 fix PCI I/O allocation: 4 byte -> 64 bit registers...
	; pd 990216 rewrite I/O allocation	
	; pd 980728 change to call postcode routine
	; pd 980728 fix PCI_NORST option -> skip entire device, not just
	;           function

	;
	; To make this BIOS more suitable for future hot plug PCI support,
	; the PCI bus address space allocation has been designed to use
	; minimum granularity and fixed size allocation for bridges, rather
	; than packing things as tightly as possible. This also simplifies
	; the code quite a bit.
	;
	; Limitations:
	;
	; - PCI bridge code not yet tested.
	; - Fixed size allocation for bridges (better to support future
	;   hot plug, simpler). As implemented, this does not work for
	;   more than 2 levels of bridges.
	; - VGA through bridge is not supported (bad idea for performance).
	; - Except for VGA BIOS, expansion ROMs are not supported.
	;   Assume first image, 32 KB size.
	; - Memory allocation below 1MB does not handle memory holes.
	;
	; PCI inherent limitations:
	;
	; - Devices behind bridges don't support memory that must be
	;   allocated below 1MB.
	;
	; PCI configuration space structure
	;
p_id	equ	0	;vendor, device ID
p_cmd	equ	4	;command register
p_stat	equ	6	;status register
p_class	equ	8	;class code, revision ID
p_linesz	equ	12	;cache line size
p_lat	equ	13	;latency timer
p_hedt	equ	14	;header type
p_bist	equ	15	;built-in self test
p_base	equ	10h	;base address registers
pb_bus	equ	18h	;bridge: primary bus number
pb_bus2	equ	19h	;bridge: secondary bus number
pb_bus3	equ	1ah	;bridge: subordinate bus number
pb_lat2	equ	1bh	;bridge: secondary latency timer
pb_io	equ	1ch	;bridge: I/O limit
pb_stat	equ	1eh	;bridge: secondary status
pb_mem	equ	20h	;bridge: memory base low
pb_memp	equ	24h	;bridge: prefetchable memory base
p_cis	equ	28h	;end of base address registers
pb_mem2	equ	28h	;bridge: memory base high
pb_memp2	equ	2ch	;bridge: prefetchable memory base high
p_rom	equ	30h	;expansion rom base
pb_io2	equ	34h	;bridge: I/O base high
pb_rom	equ	38h	;bridge: ROM
p_line	equ	3ch	;IRQ assigned to function
p_pin	equ	3dh	;0 = not used, 1=A, 2=B, 3=C, 4=D
p_mingnt	equ	3eh	;minimum grant time
pb_ctl	equ	3eh	;bridge: control
p_maxlat	equ	3fh	;maximum latency
	;
	; working variables for PNP
	;
	;+ must directly follow previous variable !
	;
	struc	tmp_pci
	
p_int:	dw	?,?	;PCI interrupt lines, LSB = INTA,
			;MSB = INTD
p_irqpt:	dw	?	;pointer to IRQ table entry
p_mem:	dw	?	;regular memory (64K steps)
p_memlim:	dw	?	;+ memory limit
p_memp:	dw	?	;prefetchable memory (64K steps)
p_memplim: dw	?	;+ prefetchable memory limit
p_io:	dw	?	;I/O address	(16 byte steps)
p_iolim:	dw	?	;+ I/O limit
p_memr:	dw	?	;memory below 1MB (segment value)
p_memrlim: dw	?	;+ limit
p_capa	dw	?	;low: 0 if back to back mode supported
			;high: 0 for fast, 2 for medium, 4/6
			;slow devsel
p_bus:	db	?	;current bus
p_lastbus: db	?	;+ last bus number
	ends
	;
	; get byte [EBX] -> AL
	;
pci_getb:	mov 	eax,ebx	;set index
	mov	dx,pci_ad
	and	al,0fch	;mask low bits
	out 	dx,eax
	mov	dl,bl	;I/O port index
	or	dl,0fch	;pci_dat assume $fc + bit mask
	in	al,dx
	ret
	;
	; get word [EBX] -> AX
	;
pci_getw:	mov 	eax,ebx	;set index
	mov	dx,pci_ad
	and	al,0fch	;mask low bits
	out 	dx,eax
	mov	dl,bl	;I/O port index
	or	dl,0fch	;pci_dat assume $fc + bit mask
	in	ax,dx
	ret
	;
	; get double word [EBX] -> EAX
	;
pci_getd:	mov 	eax,ebx	;set index
	mov	dx,pci_ad
	out 	dx,eax
	mov	dl,low(pci_dat)
	in 	eax,dx
	ret
	;
	; assign interrupts to device [EBX]
	;
pci_airq:	mov	bl,p_pin	;which interrupt pin does device use ?
	call	pci_getb
	mov	ah,0
	sub	al,1	;0 -> FF
	mov	si,ax
	jb	pci_airq3	;0 -> FF = no interrupt
	cmp	al,3
	mov	al,0ffh
	ja	pci_airq3	;out of range -> FF = no interrupt
	mov	al,[si+p_int]	;get interrupt connected to this line
pci_airq3: mov	bl,p_line	;store interrupt number
	;V fall through
	;
	; set byte AL -> [EBX]
	;
pci_setb:	push	ax
	mov 	eax,ebx	;set index
	mov	dx,pci_ad
	and	al,0fch	;mask low bits
	out 	dx,eax
	pop	ax
	mov	dl,bl	;I/O port index
	or	dl,0fch	;assume pci_dat $fc + bit mask
	out	dx,al
	ret
	;
	; set word AX -> [EBX]
	;
pci_setw:	push	ax
	mov 	eax,ebx	;set index
	mov	dx,pci_ad
	and	al,0fch	;mask low bits
	out 	dx,eax
	pop	ax
	mov	dl,bl	;I/O port index
	or	dl,0fch	;assume pci_dat $fc + bit mask
	out	dx,ax
	ret
	;
	; set double word EAX -> [EBX]
	;
pci_setd:	xchg 	eax,ebx
	mov	dx,pci_ad
	out 	dx,eax
	xchg 	eax,ebx
	mov	dl,low(pci_dat)
	out 	dx,eax
	ret
	;
	; allocate space for a device, CL = ending index
	; (different for normal device / bridge)
	;
pci_dev:	mov	bl,p_base
pci_dev1:	mov 	eax,0ffffffffh	;find out how many valid bits
          call	pci_setd	;write
          call	pci_getd	;and read back
         	mov	ch,al	;save register type
	test	al,1	;I/O ?
	jz	pci_dev1a	;:no
	and	ax,ax	;high bit set ? (D15)
	jns	pci_dev9	;no: this register doesn't work
	jmp	pci_io	;allocate I/O device
	
pci_dev1a: and 	eax,eax	;high bit set ? (D31)
	jns	pci_dev9	;no: this register doesn't work !
	test	al,2	;below 1 MB ?
	jnz	pci_memr
	mov	si,p_memp
	test	al,8	;prefetchable ?
	jnz	pci_dev2	;:yes
	mov	si,p_mem
	
	; allocate memory (normal or prefetchable)
	;
	; we allocate with a minimum of 64KB granularity
	
pci_dev2:	shr 	eax,16	;/ 64KB
	not 	ax	;get requested block size
	cmp	ax,P_MEMINC-1	;round up to minimum increment
	ja	pci_dev3
	mov	ax,P_MEMINC-1
pci_dev3:	test	[si],ax	;do we need to round up base ?
	jz	pci_dev4	;:no
	or	[si],ax	;round up base
	inc	word [si]
	jz	pci_err2	;:overflow
pci_dev4:	inc	ax	;size + 1
	add	ax,[si]	;update base
	jb	pci_err2	;overflow: error
	cmp	ax,[si+2]	;exceed limit ?
	ja	pci_err2	;:yes
	xchg	ax,[si]	;set new base, get starting base
	shl 	eax,16	;-> high word, low base is 0
pci_dev7:	call	pci_setd	;set base register
pci_dev8:	test	ch,4	;64 bit base register ?
	jz	pci_dev9	;:32 bit
	add	bl,4
	xor 	eax,eax	;clear high register
pci_dev8a: call	pci_setd
pci_dev9:	add	bl,4
	cmp	bl,cl	;end of registers ?
	jb	pci_dev1	;:try another
	ret
	
pci_err2:	mov	al,0c2h	;& error code
	jmp	pci_err9
	
pci_err3:	mov	al,0c3h	;& error code
	jmp	pci_err9
	
pci_err4:	mov	al,0c4h	;& error code
	jmp	pci_err9
	;
	; Allocate <1MB memory space
	;
pci_memr:	test	al,4	;reserved type ?
	jnz	pci_err4	;:yes
	not 	eax	;find out requested block size
	shr 	eax,4	;/16
	test 	eax,0ffff0000h	;error if device wants more than 1MB !
	jnz	pci_err3
	cmp	ax,P_MEMRINC-1	;round up to minimum increment
	ja	pci_memr2
	mov	ax,P_MEMRINC-1

	;&&& need to add base rounding

pci_memr2: add	ax,[p_memr]	;update base
	jb	pci_err2	;overflow: error
	cmp	ax,[p_memrlim]	;exceed limit ?
	ja	pci_err2	;:yes
	xchg	[p_memr],ax	;get old base, set new
	shl 	eax,4	;-> get back into place
			;(high EAX is 0 from 1MB test)
	jmp	short pci_dev7	;set base register, continue
	;
	; Allocate I/O space
	;
	; Note that I/O is allocated in 256 byte blocks starting at
	; $1000, $1400, etc. (aliases of chipset registers 0000..00FF)
	;
	; Space in x100 .. x3FF is reserved for ISA bus. Space in 0000..00FF
	; and 0480..04FF is reserved for chipset peripherals. 0CF8..0CFF is
	; the PCI config address. So we usually start at 1000.
	;
pci_io:	not	ax	;find out requested block size
	test	ax,0ff00h	;> 256 bytes ?
	jnz	pci_err5	;:error
	or	ax,P_IOINC-1	;minimum allocation
	
	test	[p_io],ax	;do we need to round up ?
	jz	pci_ior2	;:no
	or	[p_io],ax	;base must be multiple of block size
	inc	word [p_io]
	test	word [p_io],0300h	;block overrun ?
	jz	pci_ior2	;:no
	or	word [p_io],03ffh	;next 1024 byte block
	inc	word [p_io]
	jz	pci_err5	;:overflow
pci_ior2:
	inc	ax	;mask -> count
	add	ax,[p_io]	;base + block size -> future base
	test	ax,0300h	;block overrun ?
	jz	pci_ior3	;:no
	or	ax,03ffh	;next 1024 byte block
	inc	ax
	jz	pci_err5	;:overflow
pci_ior3:	cmp	ax,[p_iolim]	;exceeded limit ?
	ja	pci_err5	;:overflow

	xchg	[p_io],ax	;get old base, set new
	and 	eax,0ffffh	;clear high half of EAX
	jmp	pci_dev8a	;set base register, continue
	
pci_err5:	mov	al,0c5h	;& error code
	jmp	pci_err9
	;
	; round up [SI], mask CL, set limit using DX if primary bus,
	; DI if secondary bus
	;
pci_rnd:	mov	ax,[si]
	test	al,cl
	jz	pci_rnd1
	or	al,cl
	inc	ax
	jz	pci_err1
	mov	[si],ax
pci_rnd1:	cmp	byte [p_bus],0	;primary bus ?
	jnz	pci_rnd2
	add	ax,dx	;primary bus limit
	jmp	short pci_rnd3
	
pci_rnd2:	add	ax,di	;secondary bus limit
pci_rnd3:	jb	pci_err1	;:too much
	mov	[si+2],ax	;set limit
	ret

pci_err1:	jmp	pci_bus9	;allocation error
	;
	; allocate space for a bridge
	;
pci_bri:	inc 	byte [p_lastbus]	;get a new bus number
	mov	ax,[p_bus]	;+ lastbus
	mov	bl,pb_bus	;set primary, secondary bus number
	call	pci_setw
	mov	ax,P_SECLAT * 256 + 0ffh	;subordinate = 255 for config
	mov	bl,pb_bus3	;+ pb_lat2
	call	pci_setw

	; save variables for recursion	

	mov	al,[p_lastbus]	;save old bus number, set new
	xchg	al,[p_bus]
	push	ax
	push	[p_memlim]
	push	[p_memplim]
	push	[p_iolim]
	
	;bridges don't have fine granularity - start at 1MB / 4K boundaries
	
	mov	si,p_mem	;memory: 1MB boundaries
	mov	dx,P_MEMINC1	;primary bus
	mov	di,P_MEMINC2	;secondary bus
	mov	cl,0fh

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -