!************************************************************************** !* !* Scan memory for option roms !* !* Module: doscan.S !* Purpose: Scan memory for option roms !* Entries: _doscan !* !************************************************************************** !* !* Copyright (C) 1998-2003 Gero Kuhlmann !* !* 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 !* 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., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: doscan.S,v 1.4 2003/01/25 23:29:43 gkminix Exp $ !* ! !************************************************************************** ! ! Include header files ! #include #define IN_ASM_MODULE 1 #include "romcheck.h" ! !************************************************************************** ! ! Definitions for signature scanning ! MAXSIGS equ 16 ! maximum number of ROM signatures SIGSTEP equ $0020 ! steps for scanning for rom signature ROMSIG equ $AA55 ! rom signature MINSIZE equ $04 ! minimum rom size (2kB) SIGOFS equ $0000 ! offset to rom signature SIZEOFS equ $0002 ! offset to rom size byte ! Definitions for physical memory scanning ROMSTEP equ $0100 ! steps for scanning for physical rom ROMCHKSIZE equ $0080 ! size of check area for unknown memory ROMBSIZE equ (ENDSEG-STARTSEG) / ROMSTEP ! rom info buffer size ! Definitions for checking for netboot bootrom DATAOFS equ $0008 ! same as in the bootrom definition MAJOROFS equ DATAOFS + 0 ! offset to major version number MINOROFS equ DATAOFS + 1 ! offset to minor version number SIG1OFS equ DATAOFS + 8 ! offset to bootrom signature ! Definitions for finding a FlashCard CMDOFS1 equ $2AAA ! first command address CMDOFS2 equ $5555 ! second command address CMDOP1 equ $55 ! first command opcode CMDOP2 equ $AA ! second command opcode AMD_ID equ $2001 ! flash EPROM ID, only support AMD READID_CMD equ $90 ! command to read chip ID RESET_CMD equ $F0 ! command to reset chip state machine ! !************************************************************************** ! ! BSS segment ! .bss .lcomm sigsegs,(MAXSIGS + 1) * 2 ! segments of rom signatures .lcomm sigsize,(MAXSIGS + 1) * 2 ! size of roms in paragraphs .lcomm sigvalid,(MAXSIGS + 1) * 2 ! flags for valid checksums .lcomm sigcpyrt,(MAXSIGS + 1) * 2 ! copyright offset buffer .lcomm rombuf,ROMBSIZE + 2 ! physical rom info buffer ! !************************************************************************** ! ! Start of code segment ! .text public _doscan ! define entry points ! !************************************************************************** ! ! Scan the ROM memory. ! Input: 1. Arg - Pointer to scaninfo buffer ! Output: none ! Registers changed: AX, BX, CX, DX _doscan: cld push bp mov bp,sp mov bp,[bp + 4] ! get pointer to scaninfo buffer push es ! note that this assumes SS=DS push si push di ! Scan the ROM memory and save all segment addresses. If we found a rom ! signature, grab the ROM size and check that its OK: it has to be a ! multiple of 2kB. Then verify the checksum. If thats not OK, it may ! mean that we dont have a ROM here, or that the ROM is not com- ! pletely activated. Insert the signatures segment address into the ! table anyway but mark it as invalid. xor bx,bx mov dx,#STARTSEG scan1: cmp dx,#ENDSEG ! reached end of scan memory? jae scnend mov es,dx seg es cmp word ptr (SIGOFS),#ROMSIG ! check rom signature je scan3 scan2: add dx,#SIGSTEP ! continue with next step jmp scan1 scan3: seg es mov al,byte ptr (SIZEOFS) ! get size byte mov ah,#MINSIZE scan4: cmp al,ah ! find size in valid values je scan5 shl ah,#1 ! continue with next size jnc scan4 jmp scan2 ! size not found, continue scan scan5: mov sigsegs[bx],dx ! size found, save segment of signature mov cl,#5 xor ah,ah ! convert rom size into paragraphs shl ax,cl mov sigsize[bx],ax ! save rom size call chksum ! verify checksum jz scan6 xor ax,ax ! mark signature as invalid add dx,#SIGSTEP ! continue with next step jmp scan7 scan6: mov ax,#1 ! mark signature as valid add dx,sigsize[bx] ! continue scan past current ROM scan7: mov sigvalid[bx],ax ! save validity flag add bx,#2 ! increment signature index cmp bx,#MAXSIGS * 2 jb scan1 ! dont continue past buffer size scnend: shr bx,#1 ! prepare return values mov si_signum[bp],bx mov word ptr si_sigsegs[bp],#sigsegs mov word ptr si_sigsize[bp],#sigsize mov word ptr si_sigvalid[bp],#sigvalid ! Now scan for physical ROM. This is similar to the above loop in that ! the same memory area is scanned, but with a 4kB granularity. If we find ! an area where its not possible to write in, this doesnt necessarily ! mean we have a rom. If that area contains just one single value in ! all bytes its either not a rom at all or an empty rom. We mark it ! as unknown. This check is only done for the first 2kB of the total ! 4kB block. mov ax,ds mov es,ax ! ES:DI - pointer into rom buffer mov di,#rombuf mov si,bx ! SI - end of signature tables shl si,#1 xor bx,bx ! BX - index into signature tables mov dx,#STARTSEG roms1: cmp dx,sigsegs[bx] ! check if below current signature seg jb roms4 mov cx,sigsize[bx] ! compute end paragraph of current add cx,sigsegs[bx] ! signature segment cmp dx,cx jae roms2 ! check if within current signature seg test word ptr sigvalid[bx],#$00FF jz roms4 ! when invalid do normal memory scan call chkram ! when within a valid rom signature area mov al,#TYPE_RAM ! we distinguish only between RAM and jz roms9 ! ROM and dont check for UNKNOWN mov al,#TYPE_ROM jmp roms9 roms2: cmp bx,si jae roms4 ! if above current signature seg advance add bx,#2 ! to next segment until reaching end jmp roms1 ! of all segments roms4: call chkram ! check if paragraph is in ram mov al,#TYPE_RAM ! identify ram in info buffer jz roms9 mov ax,#ROMCHKSIZE call chkequ ! check if paragraph contains only mov ah,al mov al,#TYPE_ROM ! we found some real rom jnz roms9 mov al,#TYPE_EMPTY or ah,ah ! if the area contains all the same jz roms9 ! byte value, check if thats $00 or cmp ah,#$FF ! $FF. Use a smaller dot for displaying je roms9 ! these mov al,#TYPE_UNKNOWN roms9: stosb ! save ram character into buffer add dx,#ROMSTEP ! continue with next step cmp dx,#ENDSEG jb roms1 sub di,#rombuf ! prepare return values mov word ptr si_romsize[bp],di mov word ptr si_rombuf[bp],#rombuf ! Scan through all signature rom areas and try to identify one with the ! netboot signature. mov bx,si_signum[bp] or bx,bx ! no netboot rom if no rom areas jz nonb dec bx shl bx,#1 nbscan: mov dx,sigsegs[bx] call fndnb ! identify each rom area in turn jnc nbscn1 sub bx,#2 ! continue with next rom area jnc nbscan nonb: mov bx,#-1 xor ax,ax ! no netboot rom found jmp nbscn2 nbscn1: shr bx,#1 nbscn2: mov si_nbindex[bp],bx ! save values found mov si_nbmajor[bp],ah mov si_nbminor[bp],al ! Scan through all signature rom areas and try to find a copyright string. mov bx,si_signum[bp] or bx,bx ! dont scan if no rom areas found jz nocp dec bx shl bx,#1 cpscan: mov dx,sigsegs[bx] call fndcpy ! find a copyright string in rom area mov sigcpyrt[bx],ax sub bx,#2 ! continue with next rom area jnc cpscan nocp: mov word ptr si_sigcpyrt[bp],#sigcpyrt ! Find a FlashCard call flash ! find FlashCard and save its segment mov si_flashseg[bp],bx pop di pop si pop es pop bp ret ! !************************************************************************** ! ! Verify ROM checksum ! Input: AX - ROM size in paragraphs ! DX - ROM start segment ! Output: Zero flag cleared if checksum is not correct ! Registers changed: AX ! chksum: cld push ds push si push bx push cx push dx or ax,ax ! nothing to do for zero size jz chks9 mov bx,ax xor ah,ah ! checksum goes into AH chks1: mov ds,dx mov cx,#16 ! check one paragraph xor si,si chks2: lodsb ! load next byte from paragraph add ah,al ! add it to checksum loop chks2 inc dx ! continue with next paragraph dec bx jnz chks1 or ah,ah ! set zero flag according to checksum chks9: pop dx pop cx pop bx pop si pop ds ret ! !************************************************************************** ! ! Check if a paragraph is within a ram ! Input: DX - paragraph address ! Output: Zero flag set if paragraph is in ram ! Registers changed: AX ! chkram: push cx push es cli ! this is sensitive to interrupts mov es,dx seg es mov ax,word ptr (0) ! load first word of paragraph mov cx,ax not ax ! negate word and write it back seg es mov word ptr (0),ax seg es cmp word ptr (0),ax ! check if we could write the new value seg es mov word ptr (0),cx ! restore old value in case this was ram sti pop es pop cx ret ! !************************************************************************** ! ! Check if a ROM area contains all the same byte values ! Input: AX - ROM size in paragraphs ! DX - ROM start segment ! Output: AL - Value of first byte of ROM area ! Zero flag set if all bytes are the same ! Registers changed: AX ! chkequ: cld push es push di push bx push cx push dx or ax,ax ! nothing to do for zero size jz chke9 mov bx,ax mov es,dx seg es mov al,byte ptr (0) ! compare value goes into AL chke1: mov es,dx mov cx,#16 ! check one paragraph xor di,di repe scasb jnz chke9 inc dx ! continue with next paragraph dec bx jnz chke1 chke9: pop dx pop cx pop bx pop di pop es ret ! !************************************************************************** ! ! Identify a rom area as a netboot bootrom. ! Input: DX - paragraph of rom area ! Output: AH - major version number of bootrom ! AL - minor version number of bootrom ! Carry flag set if bootrom not found ! Registers changed: AX ! fndnb: cld push bx push cx push si push di push es mov es,dx mov di,#SIG1OFS ! check product name string, e.g. mov si,#nbsig1 ! bootrom signature mov cx,#nbsig1e - nbsig1 repe cmpsb je fndnb2 ! Couldnt find new bootrom signature, so try to find an old identifying ! string within the first 512 bytes of rom area. xor bx,bx fndnb1: mov di,bx mov si,#nbsig2 mov cx,#nbsig2e - nbsig2 ! find identifying signature repe ! within the first $0200 bytes cmpsb ! of rom area je fndnb2 inc bx cmp bx,#$0200 + nbsig2 - nbsig2e jbe fndnb1 fndnb8: stc ! signature not found jmp fndnb9 fndnb2: seg es mov ah,byte ptr (MAJOROFS) ! get major version number cmp ah,#VER_MAJOR ! has to be identical with current jne fndnb8 ! major version number seg es mov al,byte ptr (MINOROFS) ! get minor version number cmp al,#VER_MINOR ! has to be lower or equal to current ja fndnb8 ! minor version number clc fndnb9: pop es pop di pop si pop cx pop bx ret ! !************************************************************************** ! ! Find a copyright string in a rom area ! Input: DX - paragraph of rom area ! Output: AX - offset to copyright text (0 if not found) ! Registers changed: AX ! fndcpy: cld push bx push cx push si push di push es mov es,dx xor bx,bx fndcp1: mov di,bx mov si,#cpyrt mov cx,#cpyrte - cpyrt ! find copyright string repe ! within the first $0200 bytes cmpsb ! of rom area je fndcp9 inc bx cmp bx,#$0200 + cpyrt - cpyrte jbe fndcp1 fndcp8: xor bx,bx ! no copyright text found fndcp9: mov ax,bx pop es pop di pop si pop cx pop bx ret ! !************************************************************************** ! ! Try to find a FlashCard with an AMD flash EPROM. ! Input: none ! Output: BX - segment of flash eprom, or zero if not found ! Registers changed: AX, BX ! flash: push es mov bx,#STARTSEG flash1: mov es,bx call readid ! read flash EPROM ID jnc flash3 cmp bx,#ENDSEG ! dont go into BIOS ROM area jae flash2 add bx,#ROMSTEP ! continue with block jmp flash1 flash2: xor bx,bx ! no flash EPROM found flash3: pop es ret ! !************************************************************************** ! ! Read manufacturer ID from Flash-EPROM. This routine is used to scan ! through the upper data area to look for a Flash-EPROM. Since it is ! possible to run into some RAM area (for example dual-ported ram of ! a network card), we have to preserve all bytes which are changed, ! and the whole process has to be atomic. ! ! Input: ES - segment of Flash EPROM ! Output: Carry flag set, if not a Flash EPROM at current segment ! Changed registers: AX ! readid: push bx push cx push dx seg es ! if we can read the AMD ID already, mov ax,[0x0000] ! this cannot be a Flash EPROM: the cmp ax,#AMD_ID ! bootrom doesnt start with this ID je rdid8 ! and an empty Flash EPROM has all 0xFF mov cx,#3 ! set number of retries rdid1: cli ! disable all interrupts seg es mov dl,byte ptr [CMDOFS1] ! save command bytes seg es mov dh,byte ptr [CMDOFS2] mov al,#READID_CMD call sendop ! send READID command seg es mov bx,[0x0000] ! read manufacturer ID mov al,#RESET_CMD call sendop ! reset chip seg es mov byte ptr [CMDOFS1],dl ! restore command bytes seg es mov byte ptr [CMDOFS2],dh sti ! re-enable all interrupts again cmp bx,#AMD_ID ! check for correct ID je rdid9 loop rdid1 ! retry rdid8: stc ! not found, return error rdid9: pop dx pop cx pop bx ret ! !************************************************************************** ! ! Send OP code to Flash-EPROM. This involves writing three bytes into the ! flash EPROM at exactly specified locations. See AMD data sheets for ! further information. ! Input: AL - command byte ! ES - segment of Flash-EPROM ! Output: none ! Registers changed: none sendop: seg es mov byte ptr [CMDOFS2],#CMDOP2 jcxz sndop1 sndop1: jcxz sndop2 sndop2: seg es mov byte ptr [CMDOFS1],#CMDOP1 jcxz sndop3 sndop3: jcxz sndop4 sndop4: seg es mov byte ptr [CMDOFS2],al ret ! !************************************************************************** ! ! Data segment ! .data nbsig1: .asciz 'netboot' ! signature to identify a netboot nbsig1e: ! bootrom nbsig2: .ascii 'Uncompressing... ' ! old netboot bootrom strings .byte 0 .ascii 'done' .byte $0D,$0A,0 nbsig2e: cpyrt: .ascii 'Copyright' ! copyright string to look for cpyrte: ! !************************************************************************** ! end