home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
memtest.asm
< prev
next >
Wrap
Assembly Source File
|
1989-09-04
|
26KB
|
1,181 lines
page 82,120
title MemTest - Test Main & Extended Memory
.MODEL SMALL
.386p
; Gene Czarcinski, 4 Sep 89
;
; This program is designed to test main and extended (not expanded)
; (ram) memory on a 386 or 386SX. It was developed on a Wave Mate
; Bullet-386SX and some of the ports or hardware values may differ on
; different systems. Because it was developed on a 386, some of the
; specific characteristics of a 386 are used (however, it should be
; possible to convert this program to a 286 with some effort).
;
; NOTE that this program operates in REAL mode to test main memory
; and in 386 PROTECTED mode to test extended memory.
;
; This program owes some of its features and code to some other
; programs and some books (with programs):
; - RAMHAM by Clifford A. McCullough
; - 80386 A Programming and Design Handbook, 2nd Ed.
; by Penn Brumm and Don Brumm
; - Dr. Dobb's Toolbook of 80286/80386 Programming
; Edited by Phillip Robinson
; Finding enough CORRECT information to write this program was a bit
; of a problem - much of it was trial and error (plus the usual set
; of coding/typing errors -- interesting results when a segment reg
; is incorrect in protected mode).
;
; Writing this program was motivated by some memory errors on my
; Wave Mate system board. The bad memory caused a Parity Error
; but not until after the system was up (it did not fail the BIOS
; memory test). The error turned out to be a bad 1meg chip which
; had a bad section of memory (1 chip, 1 bit, 256k bits). This program
; found the error and when I replaced the chip, I had no more problems.
; I hope this may be of use to others.
;
; Note that error handling is VERY PRIMATIVE - the objective was to
; find the memory errors in the extended memory, not to create a full
; environment for the 386 (although some interrupt handling, etc. is
; necessary). This is NOT a turn-key program and some "fiddling" will
; be necessary to get it to work on other systems.
;
; The NMI Parity Error Disable/Enable value may differ. The port
; and values (bit) which indicate a Parity Error may (will) differ -
; these were quessed at since they were added AFTER the problem was
; fixed.
;
; Some simple run-time options:
;
; -f .. fast mode, very short display pause if error
; -x .. skip check for parity error
; -a .. 20 cycles of main memory checking
; -b .. 100 cycles of main memory checking
; -c .. 20 cycles of extended memory checking
; -d .. 100 cycles of extended memory checking
; default is 10 cycles each
;
; Note that errors or program completion cause the program to
; hang in a spin-loop which will require a RESET or the Big-Red-
; Switch power cycle to "terminate" (this was simple) so that messages
; are left on the video screen.
; Equates
Line00 equ 0 ; Video Ram Displacements
Line01 equ 160
Line02 equ 160*2
Line03 equ 160*3
Line04 equ 160*4
Line05 equ 160*5
Line06 equ 160*6
Line07 equ 160*7
Line08 equ 160*8
Line09 equ 160*9
Line10 equ 160*10
Line11 equ 160*11
Line12 equ 160*12
Line13 equ 160*13
Line14 equ 160*14
Line15 equ 160*15
Line16 equ 160*16
Line17 equ 160*17
Line18 equ 160*18
Line19 equ 160*19
Line20 equ 160*20
Line21 equ 160*21
Line22 equ 160*22
Line23 equ 160*23
Line24 equ 160*24
INTa01 equ 021h ; 8259 Controller #1
INTa02 equ 0A1h ; 8259 Controller #2
Port_a equ 060h ; 8042 Port A
Port_b equ 061h ; 8042 Port B
Port_c equ 062h ; 8042 Port C
Port_Status equ 064h ; 8042 Status Port
Port_Par equ 061h ; on WaveMate, others use 062h
Bits_Par equ 080h ; on WaveMate 062h, other use 0C0h on 62h
NMIPort equ 070h ; to disable/enable parity checking
Port_cmos equ 070h ;
bit20_disable equ 11011101b ; 8042 function code to degate A20
bit20_enable equ 11011111b ; 8042 function code to GATE A20
; to run protected on AT, need to enable bit20 so 386 controls the
; address line.
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Macros and Structures ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Convert 8086 segment register value to a linear address
segadr macro segr
sub eax,eax ; clear reg
mov AX,&segr ; get the segment reg
shl EAX,4 ; convert to a linear addr
endm
; Convert an 8086 segment to linear addr in a segment descriptor
segcvt macro segr,segm
segadr segr
mov segm&.base_l,AX ; get base of data
shr EAX,8 ; to AH
mov segm&.base_m,AH ; and set mid-range byte
endm
; Display Message
Vtype macro msg,len,line
mov si,offset msg ; addr of msg
mov cx,len ; length of message
mov di,line ; offset into screen
call Video_Output
endm
; Define Descriptor Structure
desc struc
limit dw 0 ; offset to last byte
base_l dw 0 ; low 16 bits of base addr
base_m db 0 ; bits 16-23 of base addr
access db 0 ; access privledges
gran db 0 ; Granularity and limit
base_h db 0 ; bits 24-31 of base addr
desc ends
; Similar to a descriptor, describe the GATE control block
gate struc
addr_l dw 0 ; Destinations's offset 0...15
select dw 0 ; Destinations's Segment Selector
db 0
gate_t db 8Eh ; type, DPL
addr_h dw 0 ; offset 16...31
gate ends
; Describe the stack of the level 0 interrrupt handler.
stkdef struc
oldip dw 0 ; 0..15 of EIP
dw 0
oldcs dw 0 ; CS
dw 0
oldfl dw 0 ; 0..15 of EFLAGS
dw 0
oldsp dw 0 ; 0..15 of SP
dw 0
oldss dw 0 ; SP
dw 0
oldes dw 0 ; ES
dw 0
oldds dw 0 ; DS
dw 0
oldfs dw 0 ; FS
dw 0
oldgs dw 0 ; GS
dw 0
stkdef ends
.CODE
assume cs:_text, ds:_text, es:_text, ss:_text
org 80h
command label byte ; tail of DOS command line
org 100h ; this is a COM file
Start: jmp Main
ALIGN 4
stack dw 800h dup(0)
stacke dw 0,0
dtsize dw 0
dtload dd 0
dsaddr dd 0
Vram dw 0b800h ; real seg of video ram
work dw 0,0,0,0
Cycle dw 0 ; Memory Test Cycles
CycleMm dw 10 ; Max Cycles for a pass Main
CycleEm dw 10 ; Max Cycles for a pass Extended
Errors dw 0 ; number of errors which occured
LoopCnt dw 0
Pause_Cnt dw 20 ; Error Pause Loop Count
Flag_CheckParity db 1 ;
ALIGN 4
MemExtnd label DWORD
MemOff dw 0 ; Current Offset
MemSeg dw 0 ; Current Segment
lastPat dw 0
Mem_Val db 0
Mem_Pat db 0
Mem_Par db 0,0
Msize dw 0 ; Main memory size
Esize dw 0 ; Extended memory size
Main_S dw 0 ; Start for main memory
Main_L dw 0 ; Limit for main memory
Extnd_Sw label WORD
Extnd_S dd 100000h ; Extended Memory Start (normal 1M or 100000h)
Extnd_Lw label WORD
Extnd_L dd 0 ; Extended Memory Limit
savecs dw 0
savess dw 0
savesp dw 0
i8259_1 db 0 ; save int status
i8259_2 db 0 ; save int status
; Memory Test Patterns
pattern db 10110010b ;par = e, B2
db 11011001b ;par = o, D9
db 01101100b ;par = e, 6C
db 10110110b ;par = o, B6
db 01011011b ;par = o, 5B
db 00101101b ;par = e, 2D
db 10010110b ;par = e, 96
db 11001011b ;par = o, CB
db 01100101b ;par = e, 65
pattern_len equ $-pattern-1
msgd1 db 'Main Memory Test Done'
msgd1L equ $-msgd1
msgd2 db 'Extended Memory Test Done'
msgd2L equ $-msgd2
msgd2o equ 80
msgd3 db 'All Testing Complete'
msgd3L equ $-msgd3
Msg1 db 'MemTest (09/04/89) Main='
Msg1a db 'xxxxxK/'
Msg1ax db 'xxxx, Extended='
Msg1b db 'xxxxxK/'
Msg1bx db 'xxxx -f='
Msg1c db ' -x='
Msg1d db ' '
Msg1Len equ $-Msg1
Msg2 db ' *** To Terminate: Reset or BRS -- Re-Boot the System ***'
Msg2Len equ $-Msg2
MsgTst db ' Test'
MsgTstL equ $-MsgTst
Msg3 db 'Write Main Segment='
Msg3ao equ ($-Msg3)*2
Msg3a db 'xxxx:0000'
Msg3Len equ $-Msg3
Msg3Leno equ ($-Msg3+4)*2
Msg4 db 'Write Extended Segment='
Msg4ao equ ($-Msg4)*2
Msg4a db 'xxxx:'
Msg4b db 'xxxx'
Msg4Len equ $-Msg4
Msg4Leno equ ($-Msg4+4)*2
Msg5 db '** Error: Address='
Msg5a db 'xxxx:'
Msg5b db 'xxxx Pattern:'
Msg5c db 'xx, Memory:'
Msg5d db 'xx, Parity:'
Msg5e db 'xx'
msg5Len equ $-Msg5
Msg7 db ' Main Memory Test Segment Start='
Msg7a db 'xxxx Limit='
Msg7b db 'xxxx Max Cycles='
Msg7d db 'xxxxx'
Msg7Len equ $-Msg7
Msg8 db 'Extended Memory Test Segment Start='
Msg8a db '0010:'
Msg8a2 db '0000 Limit='
Msg8b db 'xxxx:'
Msg8c db 'xxxx Max Cycles='
Msg8d db 'xxxxx'
Msg8Len equ $-Msg8
Msg9 db 'Cycle='
Msg9ao equ ($-Msg9)*2
Msg9a db 'xxxxx, Errors='
Msg9bo equ ($-Msg9)*2
Msg9b db 'xxxxx'
Msg9Len equ $-Msg9
Emsg3 db 'Address Line A20 failed to gate open'
Emsg3L equ $-Emsg3
; 386 Protected Mode Tables, etc.
; Define the Global Descriptor Table (GDT)
ALIGN 8
gdt_def LABEL word
d_gdt desc <> ; first one is a dummy
d_cs desc <0ffffh,0,0,10011010b,00001111b,0> ; Code
s_cs equ d_cs-gdt_def
d_ds desc <0ffffh,0,0,10010010b,00001111b,0> ; Data
s_ds equ d_ds-gdt_def
d_ss desc <0,0,0,10010110b,00000000b,0> ; Stack
s_ss equ d_ss-gdt_def
d_crt desc <0fffh,0,0,10010010b,00001111b,0> ; CRT
s_crt equ d_crt-gdt_def
d_mem desc <0fffh,0,0,10010010b,10000000b,0> ; To ref hi memory
s_mem equ d_mem-gdt_def
gdt_size equ $-gdt_def
; Define the Interrupt Descriptor Table (IDT)
ALIGN 8
idt_def LABEL WORD
gate <int00,s_cs,0,8Eh,0> ; Divide
.SALL
gate <int01,s_cs,0,8Eh,0> ; Debug
gate <int02,s_cs,0,8Eh,0> ; NMI
gate <int03,s_cs,0,8Eh,0> ; BrkPt
gate <int04,s_cs,0,8Eh,0> ; Overflow
gate <int05,s_cs,0,8Eh,0> ; Bounds
gate <int06,s_cs,0,8Eh,0> ; Invalid Opcode
gate <int07,s_cs,0,8Eh,0> ; CoProcessor Error
gate <int08,s_cs,0,8Eh,0> ; Double Fault
gate <int09,s_cs,0,8Eh,0> ; Coproc Segment Overrun
gate <int10,s_cs,0,8Eh,0> ; Invalid TSS
gate <int11,s_cs,0,8Eh,0> ; Segment Not Present
gate <int12,s_cs,0,8Eh,0> ; Stack Exception
gate <int13,s_cs,0,8Eh,0> ; General Protection
gate <int14,s_cs,0,8Eh,0> ; Page Fault
gate <intxx,s_cs,0,8Eh,0> ;
gate <int16,s_cs,0,8Eh,0> ; Coproc Error
gate <intxx,s_cs,0,8Eh,0> ; 17
gate <intxx,s_cs,0,8Eh,0> ; 18
gate <intxx,s_cs,0,8Eh,0> ; 19
gate <intxx,s_cs,0,8Eh,0> ; 20
gate <intxx,s_cs,0,8Eh,0> ; 21
gate <intxx,s_cs,0,8Eh,0> ; 22
gate <intxx,s_cs,0,8Eh,0> ; 23
gate <intxx,s_cs,0,8Eh,0> ; 24
gate <intxx,s_cs,0,8Eh,0> ; 25
gate <intxx,s_cs,0,8Eh,0> ; 26
gate <intxx,s_cs,0,8Eh,0> ; 27
gate <intxx,s_cs,0,8Eh,0> ; 28
gate <intxx,s_cs,0,8Eh,0> ; 29
gate <intxx,s_cs,0,8Eh,0> ; 30
gate <intxx,s_cs,0,8Eh,0> ; 31
REPT 224
gate <intxx,s_cs,0,8Eh,0> ; PE Interrupt Gates
ENDM
idt_size equ $-idt_def
.XALL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Entry ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Main proc near
mov ax,cs ; init real-mode seg addr
mov ss,ax
mov ds,ax
mov es,ax
mov sp,stacke-_text ; set our stack
mov ah,00h ; initialize display
mov al,3 ; video mode 3
int 10h
mov si,offset command+1 ; process any run-time options
cld
opt1: lodsb
cmp al,0dh ; C/R is end
je optend
cmp al,'-' ; option marker
jne opt1
lodsb ; option found, get next char
or al,20h ; fold to lower case
cmp al,'f' ; fast mode?
jne short opt2
mov pause_cnt,1
jmp opt1
opt2: cmp al,'x' ; skip parity check
jne short opt3
mov flag_CheckParity,0
jmp opt1
opt3: cmp al,'a' ; CycleMm=20 Main
jne short opt4
mov CycleMm,20
jmp opt1
opt4: cmp al,'b' ; CycleMm=100 Main
jne short opt5
mov CycleMm,100
jmp opt1
opt5: cmp al,'c' ; CycleEm=10 Extended
jne short opt6
mov CycleEm,20
jmp opt1
opt6: cmp al,'d' ; CycleEm=100 Extended
jne short opt7
mov CycleEm,100
jmp opt1
opt7:
jmp opt1
optend: cmp Pause_cnt,1
jne short optend1
mov Msg1c,'f'
optend1:cmp flag_checkparity,0
jne short optend2
mov Msg1d,'x'
optend2:mov ax,cycleMm
mov bx,offset Msg7d
call Convert_Decimal
mov ax,cycleEm
mov bx,offset Msg8d
call Convert_Decimal
int 12h ; get size of convensional memory
mov Msize,ax
mov bx,offset Msg1a
call Convert_Decimal
mov ax,Msize
mov bx,offset Msg1ax
call Convert_Hex
mov ah,88h ; get size of extended memory
int 15h
mov Esize,ax
mov bx,offset Msg1b
call Convert_Decimal
mov ax,Esize
mov bx,offset Msg1bx
call Convert_Hex
vtype Msg1,Msg1Len,Line03
mov Main_S,cs ; calc start of testing.
mov ax,Progend-_text
add ax,4020h
shr ax,4
add ax,Main_S
and ax,0fc00h
mov Main_S,ax
mov bx,offset Msg7a
call Convert_Hex
mov ax,Msize
shl ax,6
mov Main_L,ax
mov bx,offset Msg7b
call Convert_hex
Vtype Msg7,Msg7Len,Line04 ; Intro Msg
sub eax,eax
mov ax,Esize ; setup extended memory
or ax,ax
jz Main5 ; NO Extended Memory
add ax,0400h
shl eax,10 ; in K, mpy by 1024 to get megs
dec eax ; limit is minus 1
mov Extnd_L,EAX
mov ax,Extnd_Lw+2
mov bx,offset Msg8b
call Convert_Hex
mov ax,Extnd_Lw
mov bx,offset Msg8c
call Convert_Hex
mov ax,Extnd_Sw+2
mov bx,offset Msg8a
call Convert_Hex
mov ax,Extnd_Sw
mov bx,offset Msg8a2
call Convert_Hex
Vtype Msg8,Msg8Len,Line05
Vtype Msg2,Msg2Len,Line23
Main5:
mov al,80h ; disable the NMI interrupt
out NMIport,al
call Check_Main
mov ax,Esize
or ax,ax
jz Done ; NO Extended Memory
call Exec_Prot ; Yes, enter PE and Check it.
Done:
int 20h ; for now
Main endp
; Output a message directly to the screen - bypass any use of the BIOS
; SI=offset to msg, CX-msglength, DI=offset into screen
Video_Output proc near
push ES
mov ah,7 ; video attribute
mov ES,Vram ; video ram segment (addr or selector)
cld ; incrementing
Vout1: lodsb
stosw
dec cx
jnz Vout1
pop ES
ret
Video_Output endp
; Convert number in AX to 5 digit decimal/ASCII equivalent into
; the area (offset) pointed to by BX.
Convert_Decimal proc near
push cx
push dx
push si
mov cx,5
Conv1: mov byte ptr [BX],' ' ; clear buffer
inc bx
loop Conv1
mov si,10 ; to get digits
or ax,ax ; positive numbers only
jns Conv5
neg ax
Conv5: sub dx,dx
div si
add dx,'0'
dec bx
mov [bx],dl
or ax,ax ; done if zero
jnz Conv5
pop si
pop dx
pop cx
ret
Convert_Decimal endp
; Convert number in AL to 2 digit hex/ASCII equivalent into
; the area (offset) pointed to by BX.
Hexit proc near
push ax
and al,0fh
or al,30h
cmp al,3ah
jl Hex_al
add al,7
Hex_al: mov 1[bx],al
pop ax
shr ax,4
and al,0fh
or al,30h
cmp al,3ah
jl Hex_ah
add al,7
Hex_ah: mov [bx],al
ret
Hexit endp
; Convert number in AX to 4 digit hex/ASCII equivalent into
; the area (offset) pointed to by BX.
Convert_Hex proc near
push bx
push ax
mov al,ah
call Hexit
pop ax
add bx,2
call Hexit
pop bx
ret
Convert_Hex endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Memory bad, report error ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Bad_Mem proc near
push cx
push si
push di
push bx
mov ax,Errors
mov bx,offset Msg9b
call Convert_Decimal
Vtype Msg9b,5,Line10+Msg9bo
mov ax,MemSeg
mov bx,offset Msg5a
call Convert_Hex
mov ax,MemOff
mov bx,offset Msg5b
call Convert_Hex
mov al,Mem_Pat
mov bx,offset Msg5c
call Hexit
mov al,Mem_Val
mov bx,offset Msg5d
call Hexit
mov al,Mem_Par
mov bx,offset Msg5e
call Hexit
Vtype Msg5,Msg5Len,Line14
mov bx,pause_cnt ; pause to display msg
pause1: sub cx,cx
pause2: dec cx
jnz pause2
dec bx
jnz pause1
pop bx
pop di
pop si
pop cx
ret
Bad_Mem endp
;;;;;;;;;;;;;;;;;;;;;
; Check Main Memory ;
;;;;;;;;;;;;;;;;;;;;;
Check_Main proc near
mov ax,Main_S ; setup
mov MemSeg,ax
mov Cycle,1
mov Errors,0
mov ax,Errors
mov bx,offset Msg9b
call Convert_Decimal
Vtype Msg3,Msg3Len,Line07
Vtype Msg9,Msg9Len,Line10
Main_Loop:
mov ax,Cycle
mov bx,offset Msg9a
call Convert_Decimal
Vtype Msg9a,5,Line10+Msg9ao
mov ax,LastPat
dec ax ; start at different place each time
jge short ml1
mov ax,pattern_len
ml1: mov LastPat,ax
Vtype Msg3,MsgTstL,Line07
mov ax,Main_S ; re-init for writing
mov MemSeg,ax
; now write data to main memory
cld
mov ax,LastPat
add ax,offset pattern
mov si,ax
wm1: push si
mov ax,MemSeg
mov bx,offset Msg3a
call Convert_Hex
Vtype Msg3a,4,Line07+Msg3ao
pop si
mov es,MemSeg ; point to segment to be written
mov cx,1000h ; 4K block
sub di,di ; start at zero offset
wm5: lodsb ; put pattern byte into memory
mov es:[di],al
inc di
cmp si,offset pattern+pattern_len
jle short wm6
mov si,offset pattern
wm6: loop wm5
mov ax,MemSeg ; bump up 4k
add ax,0100h
mov MemSeg,ax
add ax,0ffh
cmp ax,Main_L
jb wm1
mov bx,pause_cnt ; pause to display msg
wm_x1: sub cx,cx
wm_x2: dec cx
jnz wm_x2
dec bx
jnz wm_x1
Vtype MsgTst,MsgTstL,Line07
mov ax,Main_S ; re-init for testing
mov MemSeg,ax
; now test the data in main memory
cld
mov ax,LastPat
add ax,offset pattern
mov si,ax
tm1: push si
mov ax,MemSeg
mov bx,offset Msg3a
call Convert_Hex
Vtype Msg3a,4,Line07+Msg3ao
pop si
mov es,MemSeg ; point to segment to be tested
mov cx,1000h ; 4K block
sub di,di ; start at zero offset
tm3: mov al,es:[di] ; check pattern byte against memory
cmp al,[si]
jne tm7 ; bad byte
mov Mem_Val,al ; save if bad parity
in al,Port_Par ; check parity
test al,Bits_Par ; shows parity error
jnz tm8
tm4: inc si
inc di
cmp si,offset pattern+pattern_len
jle tm6
mov si,offset pattern
tm6: loop tm3
jmp tm9
tm7: inc Errors
mov MemOff,di
mov Mem_Val,al
in al,Port_Par
mov Mem_Par,al
mov al,[si]
mov Mem_Pat,al
call Bad_Mem ; display
jmp tm4
tm8: inc Errors
mov MemOff,di
mov MemSeg,ES
mov Mem_Par,al
mov al,[si]
mov Mem_Pat,al
call Bad_Mem ; display
jmp tm4
tm9: mov ax,MemSeg ; bump up 4k
add ax,0100h
mov MemSeg,ax
add ax,0ffh
cmp ax,Main_L
jb tm1
mov bx,pause_cnt ; pause to display msg
tm_x1: sub cx,cx
tm_x2: dec cx
jnz tm_x2
dec bx
jnz tm_x1
mov ax,Main_S ; re-init
mov MemSeg,ax
mov ax,Cycle
inc ax
mov Cycle,ax
cmp ax,CycleMm
jle Main_loop
Vtype msgd1,msgd1L,line21
Vtype Msg9,Msg9Len,Line07+Msg3Leno
ret
Check_Main endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Initialize and Enter Protected Mode ;;
;; ... Then call Check_Extended ;;
;; ... Finally, return to real mode ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Check_Extended proc near
mov ax,s_mem ; init segment
mov GS,ax
mov Cycle,1
mov errors,0
mov ax,Errors
mov bx,offset Msg9b
call Convert_Decimal
Vtype Msg4,Msg4Len,Line08
Vtype Msg9,Msg9Len,Line10
ce1: mov ax,Cycle
mov bx,offset Msg9a
call Convert_Decimal
Vtype Msg9a,5,Line10+Msg9ao
mov ax,LastPat
dec ax ; start at different place each time
jge short ce2
mov ax,pattern_len
ce2: mov LastPat,ax
Vtype Msg4,MsgTstL,Line08
mov eax,Extnd_S ; re-init for writing
mov MemExtnd,eax
mov LoopCnt,0
; now write the data to memory
cld
mov ax,LastPat
add ax,offset pattern
mov si,ax
we1: push si
mov ax,MemSeg
mov bx,offset Msg4a
call Convert_Hex
mov ax,MemOff
mov bx,offset Msg4b
call Convert_Hex
Vtype MSg4a,9,Line08+Msg4ao
pop si
mov cx,LoopCnt
mov edi,MemExtnd ; start
we5: lodsb ; put pattern byte into memory
mov gs:[edi],al
inc edi
cmp si,offset pattern+pattern_len
jle short we6
mov si,offset pattern
we6: loop we5
mov MemExtnd,EDI
cmp edi,Extnd_L ; at end?
jnb short we_x
add edi,10000h
cmp edi,Extnd_L ; at end?
jb we1
mov edi,Extnd_L
sub edi,MemExtnd
mov LoopCnt,DI
jmp we1
we_x: mov bx,pause_cnt ; pause to display msg
we_x1: sub cx,cx
we_x2: dec cx
jnz we_x2
dec bx
jnz we_x1
Vtype MsgTst,MsgTstL,Line08
mov eax,Extnd_S ; re-init for testing
mov MemExtnd,eax
mov LoopCnt,0
; now test the memory
cld
mov ax,LastPat
add ax,offset pattern
mov si,ax
te1: push si
mov ax,MemSeg
mov bx,offset Msg4a
call Convert_Hex
mov ax,MemOff
mov bx,offset Msg4b
call Convert_Hex
Vtype Msg4a,9,Line08+Msg4ao
pop si
mov cx,LoopCnt
mov edi,MemExtnd ; start
te3: mov al,GS:[EDI] ; check pattern byte against memory
cmp al,[si]
jne te7 ; bad byte
cmp flag_CheckParity,0
je short te4
mov Mem_Val,al ; save if bad parity
in al,Port_Par ; check parity
test al,Bits_Par ; shows parity error
jnz te8
te4: inc si
inc edi
cmp si,offset pattern+pattern_len
jle short te6
mov si,offset pattern
te6: loop te3
jmp te9
te7: inc Errors ; memory did not compare
mov Mem_Val,al
mov MemExtnd,EDI
mov MemExtnd,EDI
in al,Port_Par
mov Mem_Par,al
mov al,[si]
mov Mem_Pat,al
call Bad_Mem ; display info
call Empty_8042
jmp te4
te8: inc Errors ; memory compared but parity error
mov MemExtnd,EDI
mov MemExtnd,EDI
mov Mem_Par,al
mov al,[si]
mov Mem_Pat,al
call Bad_Mem ; display info
call Empty_8042
jmp te4
te9: mov MemExtnd,edi ; at end?
cmp edi,Extnd_L
jnb short te_x
add edi,10000h
cmp edi,Extnd_L
jb te1
mov edi,Extnd_L
sub edi,MemExtnd
mov LoopCnt,DI
jmp te1
te_x: push si
mov ax,MemSeg
mov bx,offset Msg4a
call Convert_Hex
mov ax,MemOff
mov bx,offset Msg4b
call Convert_Hex
Vtype Msg4a,9,Line08+Msg4ao
pop si
mov bx,pause_cnt ; pause to display msg
te_x1: sub cx,cx
te_x2: dec cx
jnz te_x2
dec bx
jnz te_x1
mov eax,Extnd_S ; re-init
mov MemExtnd,eax
mov ax,Cycle
inc ax
mov Cycle,ax
cmp ax,CycleEm
jle ce1
Vtype msgd2,msgd2L,line21+msgd2o
Vtype Msg9,Msg9Len,Line08+Msg3Leno
ret
Check_Extended endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Interrupt Handlers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
intspv equ 1800h ; base value of interrupt handler stack
intspv1 equ 17e0h ; if no code on stack
intspv2 equ intspv1-4 ; if code IS stored
int_rdisp dw 0 ; to check SP
intcod1 dw 0 ; interrupt code word 1
intcod2 dw 0 ; interrupt code word 2
xmsg08 db 'Double Fault'
xmsg08l equ $-xmsg08
xmsg1 db 'Fault '
xmsg1a db 'xx'
xmsg1l equ $-xmsg1
; Interrupt Fault Handlers
int00: mov cx,0
mov si,0
jmp int_comm
int01: mov cx,1
mov si,0
jmp int_comm
int02: mov cx,2
mov si,0
jmp int_comm
int03: mov cx,3
mov si,0
jmp int_comm
int04: mov cx,4
mov si,0
jmp int_comm
int05: mov cx,5
mov si,0
jmp int_comm
int06: mov cx,6
mov si,0
jmp int_comm
int07: mov cx,7
mov si,0
jmp int_comm
int08: mov cx,8 ; Double Fault
mov AX,s_ds ; get some addressability
mov DS,AX
Vtype xmsg08,xmsg08l,line02
jmp $ ; SPIN - go no further
int09: mov cx,9
mov si,0
jmp int_comm
int10: mov cx,10
mov si,0
jmp int_comm
int11: mov cx,11
mov si,0
jmp int_comm
int12: mov cx,12
mov si,0
jmp int_comm
int13: mov cx,13
mov si,0
jmp int_comm
int14: mov cx,14
mov si,0
jmp int_comm
int15: mov cx,15
mov si,0
jmp int_comm
int16: mov cx,16
mov si,0
jmp int_comm
; Misc Interrupt Handler
intxx: mov cx,255
mov si,0
jmp int_comm
; Common routine for handling interrupts
int_comm:
push AX ; temp get a reg
mov ax,s_ds ; to get addressability
mov DS,AX
pop AX
pusha ; save all regs
mov AX,CX
mov BX,offset xmsg1a
call Hexit
Vtype xmsg1,xmsg1l,Line00
jmp $ ; ****DEBUG**** SPIN
popa
IretD
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This controls a signal which gates address bit 20.
;
; The gate A20 signal is an output of the 8042 slave processor.
; Address bit 20 should be gated ON before entering protect
; mode so that memory is addressed properly (if not, then odd numbered
; megs are mapped to the next lowest even numbered meg!!. When
; exiting protect mode (going back to real mode), the address A20
; should be gated back off.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Empty_8042 proc near
mov ecx,100000h ; for timeout (big number)
empty: in al,port_status ; read the 8042 status port
and al,00000010b ; test input buffer full flag
loopnz empty ; loop until empty or timeout
ret
Empty_8042 endp
Gate_A20 proc near
;
; On entry, AH contains the code (enable or disable)
;
call Empty_8042
jnz short exit_8042 ; yes
mov al,0D1h ; 8042 command to write output port (I hope)
out port_status,al
call empty_8042
jnz short exit_8042
mov al,ah
out port_a,al ; output gate signal
call empty_8042
Exit_8042:
ret
Gate_A20 endp
Exec_Prot proc near ; Setup and switch to PE
cld
cli
mov savecs,CS
mov savess,SS
mov savesp,SP
; First, Enable the A20 line
mov ah,bit20_enable
call gate_a20
or al,al ; zero if OK
jz A20_ON
Vtype Emsg3,Emsg3L,Line24
ret
A20_ON:
; Convert segment regs into linear addresses.
mov ES,Vram
segcvt ES,d_crt
mov Vram,s_crt ; Protected Mode Video
segcvt CS,d_cs
segcvt DS,d_ds
segcvt SS,d_ss
; Setup GDT, IDT, etc. to run protected
segadr DS
mov dsaddr,EAX
sub EBX,EBX
lea EBX,gdt_def
add EBX,EAX
mov dtload,EBX ; set addr
mov dtsize,gdt_size-1
LGDT FWORD PTR dtsize
sub EBX,EBX
lea EBX,idt_def
add EBX,EAX
mov dtload,EBX ; set addr
mov dtsize,idt_size-1
LIDT FWORD PTR dtsize
mov EAX,CR0 ; get control reg
or AL,1 ; turn PE on
mov CR0,EAX ; set it
jmp short @f ; clear pipeline, etc.
@@: nop
mov AX,s_ds ; and seg regs
mov DS,AX
mov ES,AX
mov FS,AX
mov GS,AX
mov AX,s_ss
mov SS,AX
db 0eah ; do far jump to set CS
dw go_prot_2-_text,s_cs
go_prot_2:
mov al,80h ; disable the NMI interrupt
out NMIport,al
call Check_Extended
; restore for real mode
cld
cli
mov EAX,CR0 ; get control reg
and AL,0FEh ; turn PE off
mov CR0,EAX ; set it
jmp go_real
go_real:
mov SS,savess
mov SP,savesp
mov AX,savecs
mov DS,AX
mov ES,AX
mov FS,AX
mov GS,AX
mov Vram,0b800h ; Restore Real Mode Video
Vtype msgd3,msgd3L,Line22
jmp $ ; SPIN - pending interrupts screwed up,
; leave video display up rather
; than re-booting.
sti
ret
Exec_Prot endp
ProgEnd equ $
_text ends
end start