mirror of
https://github.com/stevenhowes/wbios.git
synced 2026-05-26 15:53:34 +01:00
d410ad0acb
Original source https://www.pcengines.ch/file/wbios111s.zip
656 lines
14 KiB
Plaintext
656 lines
14 KiB
Plaintext
;
|
|
; POST (power on self test) routines
|
|
;
|
|
; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
|
|
; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
|
|
;
|
|
; Limitations:
|
|
;
|
|
; - Ctrl-Alt-Del does not get any special treatment by POST, goes
|
|
; through full memory test etc.
|
|
;
|
|
; pd050206 change from d_extop to d_exmem
|
|
; pd030516 changed memory test display increment to 16MB
|
|
; (faster when using serial console !)
|
|
; pd011107 add MTEST_1PASS option
|
|
; pd000424 add QUICKMEM option
|
|
; pd991127 add PS/2 mouse vector
|
|
|
|
;
|
|
; handle error: hang if C=1, return otherwise
|
|
;
|
|
post_err: jb post_err1 ;:error
|
|
ret
|
|
|
|
post_err1: cli
|
|
hlt ;hang
|
|
;
|
|
; verify BIOS checksum, return C=1 if error
|
|
;
|
|
post_sum: mov si,offset startofs ;start offset, must be multiple of 256
|
|
xor bx,bx ;clear sum
|
|
post_sum1: cs: lodsw
|
|
add bl,al
|
|
add bl,ah
|
|
cs: lodsw
|
|
add bl,al
|
|
add bl,ah
|
|
and si,si
|
|
jnz post_sum1 ;:more to test
|
|
and bl,bl ;sum = 0 ?
|
|
jnz post_stc1 ;no: error
|
|
post_clc1: clc
|
|
ret
|
|
;
|
|
; Test memory refresh (and indirectly, 8254 timer)
|
|
;
|
|
#if def NO_ISAREF
|
|
post_ref: clc ;skip test
|
|
ret
|
|
post_stc1: stc
|
|
ret
|
|
#else
|
|
post_ref: mov cx,256
|
|
post_ref1: in al,port61 ;wait for refresh bit = 0
|
|
and al,10h
|
|
jz post_ref2
|
|
loop post_ref1
|
|
post_stc1: stc ;timeout
|
|
ret
|
|
|
|
post_ref2: in al,port61 ;wait for refresh bit = 1
|
|
and al,10h
|
|
jnz post_clc1 ;yes: return clc
|
|
loop post_ref2
|
|
stc ;timeout
|
|
ret
|
|
#endif
|
|
;
|
|
; Test DMA registers
|
|
;
|
|
post_dma: mov dx,dma1 ;I/O port
|
|
mov si,2 ;port increment
|
|
post_dma1: mov di,dx ;save I/O port
|
|
mov bx,8000h ;starting pattern
|
|
post_dma2: call post_dma3 ;test
|
|
jb post_stc1 ;:error
|
|
mov dx,di ;restore I/O port
|
|
ror bx,1 ;next pattern
|
|
jnb post_dma2 ;:another bit
|
|
mov dl,dma0
|
|
shr si,1 ;do dma0 ?
|
|
jnb post_dma1 ;:yes
|
|
clc ;passed test
|
|
ret
|
|
|
|
post_dma3: mov cx,8 ;8 address and count registers
|
|
post_dma4: mov al,bl ;write test pattern (16 bit = 2 writes)
|
|
out dx,al
|
|
out iowait,al
|
|
mov al,bh
|
|
out dx,al
|
|
out iowait,al
|
|
in al,dx ;read back and compare
|
|
cmp al,bl
|
|
jnz post_stc1
|
|
out iowait,al
|
|
in al,dx
|
|
cmp al,bh
|
|
jnz post_stc1
|
|
out iowait,al
|
|
add dx,si ;next port
|
|
loop post_dma4
|
|
clc ;ok return
|
|
ret
|
|
;
|
|
; Test IRQ mask registers
|
|
;
|
|
post_irq: mov dx,pic0+1
|
|
call post_reg
|
|
jb post_irq2
|
|
mov dl,pic1+1
|
|
call post_reg
|
|
post_irq2: mov al,0ffh ;mask off all interrupts
|
|
out pic0+1,al
|
|
out pic1+1,al
|
|
ret
|
|
;
|
|
; test register [DX]
|
|
;
|
|
post_reg: mov bl,80h ;starting pattern
|
|
post_reg2: mov al,bl ;write pattern
|
|
out dx,al
|
|
not al ;write inverted pattern to prevent
|
|
out iowait,al ;capacitive hold
|
|
in al,dx ;read back
|
|
cmp al,bl
|
|
jnz post_stc1 ;:error
|
|
out iowait,al
|
|
ror bl,1 ;try next bit
|
|
jnb post_reg2
|
|
clc ;return ok status
|
|
post_reg9: ret
|
|
;
|
|
; Test DMA page registers
|
|
;
|
|
post_page: mov dx,fd_page
|
|
mov cx,15 ;81..8F
|
|
post_pag2: call post_reg
|
|
jb post_reg9 ;:error
|
|
inc dx
|
|
loop post_pag2
|
|
ret
|
|
;
|
|
; Test timer 2 registers
|
|
;
|
|
post_tim: mov al,0b0h ;timer 2
|
|
out timer+3,al
|
|
out iowait,ax ;this is needed, at least on M6117 !
|
|
out iowait,ax
|
|
#if def MEDIAGX
|
|
out timer+2,al ;dummy write, read
|
|
out timer+2,al
|
|
in al,timer+2
|
|
in al,timer+2
|
|
#endif
|
|
mov bx,1
|
|
post_tim1: mov al,bl ;LSB
|
|
out timer+2,al
|
|
out iowait,ax
|
|
mov al,bh ;MSB
|
|
out timer+2,al
|
|
out iowait,ax
|
|
in al,timer+2 ;check LSB
|
|
cmp al,bl
|
|
jnz post_stc2
|
|
out iowait,ax
|
|
in al,timer+2 ;check MSB
|
|
out iowait,ax
|
|
cmp al,bh
|
|
jnz post_stc2
|
|
shl bx,1
|
|
jnb post_tim1
|
|
clc
|
|
ret
|
|
post_stc2: stc
|
|
ret
|
|
;
|
|
; Clear registers, disable DMA, interrupts
|
|
;
|
|
post_clr: mov si,offset clrtab
|
|
jmp short post_tdm0
|
|
;
|
|
; Initialize timers, DMA
|
|
;
|
|
post_tdma: mov si,tdmatab
|
|
post_tdm0: mov dh,0
|
|
post_tdm1: cs: lodsw
|
|
cmp ah,0ffh ;end of table ?
|
|
jz post_tdm9
|
|
mov dl,ah ;port address
|
|
out dx,al ;write data
|
|
out iowait,al ;I/O wait
|
|
jmp post_tdm1
|
|
post_tdm9: ret
|
|
;
|
|
; global descriptor table (GDT) for unreal mode
|
|
;
|
|
db (($+15) and 0fff0h)-$ dup 0ffh ;even 16
|
|
gdt: dw gdtend-gdt-1 ;GDT limit
|
|
gdtadr: dw gdt,000fh ;linear address of GDT
|
|
dw 0
|
|
dw 0ffffh,0,9300h,008fh ;4G data segment, accessed
|
|
#if def GX_GDT
|
|
dw 0ffffh,0,9300h,408fh ;GX_BASE segment -> GS:
|
|
#endif
|
|
gdtend:
|
|
;
|
|
; Enter unreal (4GB segment) mode -> change DS,ES selector
|
|
;
|
|
; based on code in DDJ 7/90
|
|
;
|
|
getunreal: cli ;disable interrupts
|
|
cs: lgdt [gdt] ;load GDT (in data module, writeable)
|
|
|
|
mov eax,cr0
|
|
or al,1 ;enable protected mode
|
|
mov cr0,eax
|
|
jmp short getunrl2 ;flush queue
|
|
getunrl2: mov bx,8 ;selector
|
|
mov ds,bx
|
|
mov es,bx
|
|
and al,0feh ;exit protected mode
|
|
mov cr0,eax
|
|
ret
|
|
;
|
|
; display high memory size EBP (destroyed)
|
|
;
|
|
post_dsph: push ebp ;save EBP
|
|
#if def GX_VID
|
|
mov ax,0e0bh ;display clear to beginning of line
|
|
#else
|
|
mov ax,0e0dh ;display CR
|
|
#endif
|
|
mov bl,0
|
|
int 10h
|
|
pop eax ;EBP -> EAX
|
|
shr eax,10 ;display high memory size
|
|
;div 1024 -> KB
|
|
sub eax,1024 ;sub eax,#1024
|
|
;fall through
|
|
;
|
|
; display number EAX
|
|
;
|
|
; divide / stack based algorithm
|
|
;
|
|
post_itoa: xor dx,dx ;mark first digit on stack
|
|
push dx
|
|
mov ecx,10
|
|
post_ito2: xor edx,edx
|
|
div ecx
|
|
or dl,"0" ;remainder -> ASCII digit
|
|
push dx ;push digit
|
|
and eax,eax ;done ?
|
|
jnz post_ito2
|
|
|
|
post_ito3: pop ax ;get digit
|
|
and al,al
|
|
jz post_ito9
|
|
mov ah,0eh ;TTY output
|
|
mov bh,0 ;page 0
|
|
int 10h
|
|
jmp post_ito3
|
|
|
|
post_ito9: ret
|
|
;
|
|
; size low memory -> EBX = top address; 64KB granularity
|
|
; (run in unreal mode)
|
|
;
|
|
post_szlo: mov ebx,0a0000h ;top limit
|
|
xor ecx,ecx ;bottom limit
|
|
post_szl0: mov edx,ebx ;save top
|
|
mov edi,10000h ;64KB increment
|
|
|
|
; first, write address to memory, counting down
|
|
|
|
post_szl1: sub ebx,edi
|
|
mov [ebx],ebx
|
|
cmp ebx,ecx
|
|
jnz post_szl1
|
|
|
|
; now, verify going up
|
|
|
|
post_szl2: add ebx,edi
|
|
cmp [ebx],ebx
|
|
jnz post_szl3 ;error: done
|
|
cmp ebx,edx
|
|
jnz post_szl2
|
|
post_szl3: ret ;ebx = top address
|
|
;
|
|
; size high memory
|
|
; (run in unreal mode)
|
|
;
|
|
|
|
; first, we do binary rough size
|
|
|
|
post_szhi: xor esi,esi ;start seed
|
|
mov [esi],esi
|
|
mov ebx,00100000h ;1MB start
|
|
mov ecx,ebx ;start for szlo
|
|
post_szh1: mov [ebx],ebx
|
|
cmp [esi],esi ;wrote over previous ?
|
|
jnz post_szh2 ;:yes - reached top
|
|
cmp [ebx],ebx ;this location ok ?
|
|
jnz post_szh2 ;:no - reached top
|
|
mov esi,ebx ;new seed location
|
|
shl ebx,1
|
|
test ebx,TOP_MEM shl 16 ;reached top ?
|
|
jz post_szh1 ;:not yet
|
|
post_szh2: jmp post_szl0 ;ebx is top limit - use low size
|
|
;algorithm now for 64KB resolution
|
|
;
|
|
; Test 64 KB memory block [EBP]
|
|
; (run in unreal mode)
|
|
;
|
|
; preserve EDX !
|
|
;
|
|
post_t64k: mov edi,ebp ;starting address (must be at 64K
|
|
;multiple)
|
|
|
|
; first, do a 64 bit sliding bit test over first 64 x 64 bits
|
|
|
|
mov eax,1 ;test pattern
|
|
xor ebx,ebx
|
|
post_tk1: mov [edi],eax
|
|
mov [edi+4],ebx
|
|
add di,8
|
|
shl eax,1
|
|
rcl ebx,1
|
|
jnb post_tk1 ;:another bit
|
|
|
|
xor di,di ;return to start
|
|
mov eax,1 ;test pattern
|
|
xor ebx,ebx
|
|
post_tk2: cmp [edi],eax
|
|
jnz post_tk9 ;:error
|
|
cmp [edi+4],ebx
|
|
jnz post_tk9 ;:error
|
|
add di,8
|
|
shl eax,1
|
|
rcl ebx,1
|
|
jnb post_tk2
|
|
|
|
; now, write initial test pattern seed
|
|
; 72 bytes long -> always get distance between
|
|
; current cache line and destination
|
|
|
|
mov eax,00100100100100100100100100100100xb ;test pattern
|
|
post_tk3: mov edi,ebp ;start location
|
|
mov di,16 ;skip first 16 bytes
|
|
mov esi,edi
|
|
|
|
mov cx,18
|
|
post_tk4: a4 stosd
|
|
test al,4 ;"round" rotate
|
|
jz post_tk41 ;implicit CLC
|
|
stc
|
|
post_tk41: rcr eax,1
|
|
dec cx
|
|
jnz post_tk4 ;:another
|
|
|
|
; do block move -> copies pattern all over memory
|
|
|
|
mov ecx,16362 ;word count
|
|
a4 rep movsd
|
|
|
|
; now verify final pattern
|
|
|
|
post_tk5: cmp eax,[esi]
|
|
jnz post_tk9 ;:error
|
|
test al,4 ;"round" rotate
|
|
jz post_tk51 ;implicit CLC
|
|
stc
|
|
post_tk51: rcr eax,1
|
|
add si,4
|
|
jnz post_tk5
|
|
|
|
test al,4 ;"round" rotate
|
|
jz post_tk52 ;implicit CLC
|
|
stc
|
|
post_tk52:
|
|
|
|
#if !def MTEST_1PASS
|
|
rcr eax,1 ;try next pattern
|
|
jnb post_tk3 ;:again, total of three passes
|
|
#endif
|
|
|
|
mov edi,ebp
|
|
xor eax,eax
|
|
mov cx,16384
|
|
a4 rep stosd ;clear memory
|
|
|
|
mov ebp,edi ;new top
|
|
clc
|
|
ret
|
|
|
|
post_tk9: stc ;error return
|
|
ret
|
|
|
|
#IF DEF QUICKMEM
|
|
;
|
|
; Clear 64 KB memory block [EBP]
|
|
; (run in unreal mode)
|
|
;
|
|
; preserve EDX !
|
|
;
|
|
post_c64k: mov edi,ebp ;starting address (must be at 64K
|
|
;multiple)
|
|
xor eax,eax ;zero fill
|
|
mov ecx,4000h
|
|
a4 rep stosd ;fill
|
|
mov ebp,edi ;mov ebp,edi - new top
|
|
clc
|
|
ret
|
|
#ENDIF
|
|
;
|
|
; base memory test
|
|
;
|
|
post_base: call getunreal ;enter unreal mode
|
|
call post_szlo ;size low memory
|
|
mov [tmp_losz],ebx
|
|
|
|
mov word [m_lomem],64 ;we have at least 64KB DRAM
|
|
mov ebp,10000h ;start address
|
|
|
|
post_bas0:
|
|
#IF DEF QUICKMEM
|
|
call post_c64k ;clear 64K of DRAM
|
|
#ELSE
|
|
call post_t64k ;test 64K of DRAM
|
|
#ENDIF
|
|
jb post_bas1 ;:error
|
|
add word [m_lomem],64 ;we got another 64KB
|
|
cmp ebp,[tmp_losz]
|
|
jnz post_bas0 ;:another block
|
|
|
|
post_bas1: xor ax,ax ;access BIOS segment
|
|
mov ds,ax
|
|
mov es,ax
|
|
|
|
#if def CM_LEGACY
|
|
mov ah,cm_meml ;write base memory size to CMOS
|
|
mov al,[m_lomem]
|
|
call rtc_write
|
|
mov al,[m_lomem+1]
|
|
mov ah,cm_memh ;write low memory size
|
|
call rtc_write
|
|
#endif
|
|
ret
|
|
;
|
|
; init interrupt vectors
|
|
;
|
|
post_vec: mov si,offset inttab ;init interrupt vectors
|
|
xor di,di ;vec00
|
|
mov ax,cs ;BIOS segment -> eax bit 31..16
|
|
shl eax,16
|
|
mov cx,1fh
|
|
post_vec1: cs: lodsw ;copy vectors 00.1e
|
|
stosd ;vector + segment
|
|
loop post_vec1
|
|
add di,4 ;skip vector 1F
|
|
|
|
mov cl,60h-20h
|
|
mov ax,offset intdummy ;dummy vectors 20..5F
|
|
rep stosd
|
|
add di,8*4 ;skip 60..67
|
|
mov cl,8
|
|
rep stosd ;fill 68..6F
|
|
|
|
mov cl,8 ;copy 8 more vectors
|
|
post_vec2: cs: lodsw ;copy vectors 70..77
|
|
stosd
|
|
loop post_vec2
|
|
ret
|
|
;
|
|
; Extended memory test
|
|
;
|
|
post_ext: call getunreal ;enter unreal mode again (& cli)
|
|
|
|
push dword [0] ;save lowest memory - zapped by
|
|
;post_szhi
|
|
call post_szhi ;size high memory
|
|
pop dword [0]
|
|
|
|
mov [tmp_hisz],ebx
|
|
|
|
mov ebp,100000h ;start address
|
|
|
|
post_ext0:
|
|
#IF ! DEF QUICKMEM
|
|
test ebp,0ffffffh ;reached 16MB boundary ?
|
|
jnz post_ext1
|
|
pushad ;save all registers
|
|
call post_dsph ;display current count
|
|
call getunreal ;get back to unreal mode
|
|
popad ;restore all registers
|
|
#ENDIF
|
|
post_ext1:
|
|
#IF DEF QUICKMEM
|
|
call post_c64k ;clear 64K of DRAM
|
|
#ELSE
|
|
call post_t64k ;test 64K of DRAM
|
|
#ENDIF
|
|
jb post_ext2 ;:error
|
|
cmp ebp,[tmp_hisz]
|
|
jnz post_ext0 ;:another block
|
|
|
|
post_ext2: push ebp ;save actual top of memory
|
|
call post_dsph ;display current count
|
|
mov si,msg_ext ;display " KB Extended Memory"
|
|
call v_msg
|
|
|
|
xor ax,ax ;access BIOS segment
|
|
mov ds,ax
|
|
mov es,ax
|
|
|
|
call cs_shadrw ;shadow read/write
|
|
pop eax
|
|
push eax
|
|
sub eax,0100000 ;subtract base memory
|
|
mov dword [cs:d_exmem],eax ;store top address in data area
|
|
movzx eax,word [m_lomem]
|
|
shl eax,10 ;convert KB into actual size
|
|
mov dword [cs:d_basmem],eax
|
|
|
|
call cs_shadro
|
|
|
|
pop ebx ;store extended memory size in CMOS
|
|
shr ebx,10 ;convert to KB
|
|
cmp ebx,10000h ;limit to 64MB
|
|
jb >l1
|
|
xor bx,bx
|
|
l1: sub bx,1024 ;minus base memory
|
|
|
|
mov ah,cm_exh ;write high memory size
|
|
mov al,bh
|
|
call rtc_write
|
|
mov al,bl
|
|
mov ah,cm_exl ;write low memory size
|
|
#if def CM_LEGACY
|
|
call rtc_write
|
|
mov ah,cm_exh2 ;write high memory size
|
|
mov al,bh
|
|
call rtc_write
|
|
mov al,bl
|
|
mov ah,cm_exl2 ;write low memory size
|
|
#endif
|
|
jmp rtc_write
|
|
;
|
|
; scan for option ROMs
|
|
;
|
|
post_scan: mov ds,bx
|
|
cmp word [0],0aa55h ;start signature
|
|
jnz post_scn8 ;:no
|
|
mov cl,[2] ;get length
|
|
shl cx,9 ;* 512
|
|
xor si,si ;start offset
|
|
xor al,al ;clear sum
|
|
post_scn1: add al,[si] ;calculate checksum
|
|
inc si
|
|
loop post_scn1
|
|
mov word [es:m_ioofs],3 ;offset - call vector
|
|
mov [es:m_ioseg],ds ;segment
|
|
shr si,4
|
|
add bx,si ;update segment
|
|
cmp al,0
|
|
jnz post_scn9 ;:bad checksum
|
|
|
|
push bx ;save segment
|
|
push dx ;save limit
|
|
call far [es:m_ioofs] ;call ROM
|
|
cld ;just in case they set it...
|
|
pop dx ;restore limit
|
|
pop bx ;restore segment
|
|
jmp short post_scn9
|
|
|
|
post_scn8: add bx,0080h
|
|
post_scn9: cmp bx,dx ;top limit ?
|
|
jb post_scan ;:no
|
|
xor ax,ax ;restore segments
|
|
mov ds,ax
|
|
mov es,ax
|
|
ret
|
|
;
|
|
; Interrupt vector table
|
|
;
|
|
inttab: dw int00 ;divide by zero
|
|
dw int01 ;single step
|
|
dw nmi ;NMI
|
|
dw int03 ;breakpoint
|
|
dw int04 ;overflow
|
|
dw int05 ;print screen
|
|
dw int06 ;invalid opcode
|
|
dw int07 ;coprocessor not available
|
|
dw irq0 ;IRQ0 system timer
|
|
dw irq1 ;IRQ1 keyboard
|
|
dw inteoi ;reserved - cascade
|
|
dw inteoi ;IRQ3 reserved
|
|
dw inteoi ;IRQ4 reserved
|
|
dw inteoi ;IRQ5 reserved
|
|
dw irq6 ;IRQ6 floppy
|
|
dw inteoi ;IRQ7 reserved
|
|
dw int10 ;video
|
|
dw int11 ;equipment determination
|
|
dw int12 ;memory size
|
|
dw int13 ;disk
|
|
dw int14 ;serial
|
|
dw int15 ;system services
|
|
dw int16 ;keyboard
|
|
dw int17 ;printer
|
|
dw int18 ;expansion ROM
|
|
dw int19 ;bootstrap
|
|
dw int1a ;timer / RTC
|
|
dw int1b ;keyboard break
|
|
dw int1c ;user timer tick
|
|
dw v_parm ;video parameters
|
|
dw fd_ptab ;diskette parameters
|
|
|
|
dw irq8 ;IRQ8: RTC
|
|
dw inteoi2 ;IRQ9: cascade
|
|
dw inteoi2 ;IRQ10: spare
|
|
dw inteoi2 ;IRQ11: spare
|
|
#if def PS2MOUSE
|
|
dw irq12
|
|
#else
|
|
dw inteoi2 ;IRQ12: spare
|
|
#endif
|
|
dw irq13 ;IRQ13: spare
|
|
dw irq14 ;IRQ14: hard disk
|
|
#if def HD_4DRV
|
|
dw irq15 ;IRQ15: hard disk
|
|
#else
|
|
dw inteoi2 ;IRQ15: spare
|
|
#endif
|
|
;
|
|
; Display POST code AL
|
|
;
|
|
; This routine is called very early, without a stack.
|
|
; If you decide to display POST codes to a serial or parallel
|
|
; port, you will have to initialize the super I/O first.
|
|
;
|
|
#if ! def postcode ;can be overridden by user routine
|
|
postcode: out post,al
|
|
ret
|
|
#endif
|
|
;
|
|
; Display fatal error code AL
|
|
;
|
|
; This routine is called on fatal errors, e.g. bad memory.
|
|
; We just write the POST code, then hang.
|
|
;
|
|
#if ! def fatal ;can be overridden by user routine
|
|
fatal: out post,al
|
|
fatal1: hlt
|
|
jmp fatal1
|
|
#endif
|