From: lace <> Date: Wed, 22 Feb 2006 13:37:45 +0000 (+0000) Subject: Some working release. X-Git-Url: http://git.jankratochvil.net/?p=biosautoraid.git;a=commitdiff_plain;h=14d70cafa996a3e4f55d999ff97720a32a527427 Some working release. --- 14d70cafa996a3e4f55d999ff97720a32a527427 diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..3a67e3e --- /dev/null +++ b/.cvsignore @@ -0,0 +1 @@ +biosautoraid.bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d857aa6 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +# $Id$ + + +all: biosautoraid.bin + +biosautoraid.bin: biosautoraid.S biosautoraid.pl + $(CC) -Wall -nostdlib -Wl,--oformat,binary $< -o $@ + chmod -x $@ + ./biosautoraid.pl --bin=$@ + +.PHONY: clean +clean: + $(RM) biosautoraid.bin + diff --git a/biosautoraid.S b/biosautoraid.S new file mode 100644 index 0000000..f7f0ff5 --- /dev/null +++ b/biosautoraid.S @@ -0,0 +1,495 @@ +/* + * $Id$ + * + * Automatically retry all BIOS reads 0x80<->0x81 (and if (drive&0x80) drive^=1; in genral) + * + * Derived from: + */ +#if 0 + http://cvs.sourceforge.net/viewcvs.py/*checkout*/surprise/surprise/misc/int13sniff.S +#endif + +/* !!! All defines below must be COMMENTED-OUT ! + * !!! Define to value 0 has no effect. + */ + +/* Reduce size by omitting DOS-boot header signature to fit in 512 bytes. + * Cylinder 0 is requierd, sectors per track == 63 assumed! + * This constant is counted from 0 !!! + */ +#define BACKUP_SECTOR 63 + +/* Reduce size by omitting DOS-boot header signature to fit in 512 bytes. + */ +#define STRIP_BOOT_HEADER 1 + +/* Maintainers: Disable .org macroinstructions: ONLY FOR compilation tuning! + * - image produced doen't have any functionality! +#define DISABLE_ORG 1 + */ + +/* Internal defines */ +#define MEM_KBYTES 0x413 /* BIOS variable */ + +#define MAX_BOOT_SIZE_100 0xb6 /* LILO: leave some space for NT's and DR DOS' dirty */ +#define MAX_BOOT_SIZE (MAX_BOOT_SIZE_100+0x100) + + +/* Macros: */ + + .macro outchar char + movw $0x0E00 | \char,%ax + movw $7,%bx + int $0x10 + .endm + +#ifdef DISABLE_ORG +#define MYORG(offset) +#else +#define MYORG(offset) .org (offset) + START /* "+ START" MUST be on the end of line - WHY?!? */ +#endif + + .macro pushALL + pushw %ax + pushw %bx + pushw %cx + pushw %dx + pushw %si + pushw %di + pushw %bp + .endm + + .macro popALL + popw %bp + popw %di + popw %si + popw %dx + popw %cx + popw %bx + popw %ax + .endm + +#define PUSHALL_SIZE (7*2) +#define PUSHALL_SI ((1/*%bp*/+1/*%di*/)*2) + + .macro CallJumpVector0x13 + pushf /* create 'lret' stack by this pushf... */ + pushw %cs /* ...this segment... */ + call JumpVector0x13 /* ...and this return address */ + .endm + + + +/* Code starts here */ +/********************/ + + .arch i8086,nojumps + .code16 + .text + .globl _start +_start: + +/* init stack */ +START: + cli /* just a paranoia, shouldn't be needed */ + jmp InitRawStack /* We don't want to have 0x90 on offset 2 (one of recognization rules by DOS) */ + .org START+0x03 + + .macro places offset length string + .org (\offset) + START + .ascii "\string" + .org (\offset) + (\length) + START /* we can't check whether it isn't too short :-( */ + .endm + .macro placex offset length bytes + .org (\offset) + START + .byte \bytes + .org (\offset) + (\length) + START /* we can't check whether it isn't too short :-( */ + .endm + +/* We rather supply empty (=zeroed) FAT filesystem table + */ +#ifndef STRIP_BOOT_HEADER + places 0x03,8,"BIOSRAID" /* OEM ID */ + placex 0x43,3,"0x5E,0x81,0xA2" /* Volume Serial Number: 5E81A2?? as "SERIAL??" */ + placex 0x43+3,1,BACKUP_SECTOR /* Volume Serial Number: 5E81A23F as "SERIAL??" */ + places 0x47,11,"BIOSauRAID\0" /* Volume Label */ + places 0x52,8,"BootOnly" /* Filesystem ID */ +#else + places 0x03,8,"BIOSRAI2" /* OEM ID */ + placex 0x03+8,1,BACKUP_SECTOR /* Sanity checked by: biosautoraid.pl */ + placex 0x03+9,1,MAX_BOOT_SIZE_100 /* Sanity checked by: biosautoraid.pl */ +#endif + +InitRawStack: +#ifndef STRIP_BOOT_HEADER + .org 0x5A + START +#endif + + xorw %ax,%ax + movw %ax,%ss + movw $0x7C00,%sp + sti + outchar '1' + ljmp $0x7C0/*segment*/ , $InitContinue7C0-START/*offset*/ + +InitContinue7C0: +#if 0 + outchar '2' +#endif + +/* move to top memory */ + xorw %dx,%dx /* DX=null */ + movw %dx,%ds + movw %ds:MEM_KBYTES,%ax + decw %ax /* Allocation size: 1KB */ + movw %ax,%ds:MEM_KBYTES + movb $6,%cl + shlw %cl,%ax + movw %ax,%es + xorw %di,%di /* buffer=ES:DI */ + movw $0x7C00,%si + movw $0x200/2,%cx + rep + movsw + pushw %es + movw $InitContinueTop-START,%ax + pushw %ax + lret + +PrintTrailNL: + movw $TrailNL_Msg-START,%si + jmp PrintString_noPref + +/* String is given in SI, returns updated SI */ +PrintString: + movb $'%',%al + call PrintChar +PrintString_noPref: + pushw %cs + popw %ds +PrintString_loop: + cld + lodsb + testb %al,%al + jz Return1 + movw $PrintString_loop-START,%bx /* from now do just 'ret' to close the loop */ + pushw %bx +/* fallthru */ + +/* Character is given in AL + * Preserves: DS, ES, SI, DI + * Destroys: AX (even AL!), BX, CX, DX + * DS is sometimes left preserved, sometimes set to DS=CS + */ +PrintChar: + movb $0x0E,%ah /* print character */ + movw $7,%bx + pushw %ax + int $0x10 + popw %ax +Return1: + ret + + +SF13_02_Err_Msg: + .ascii "Read16" +SnifferErrTail_MSG: + .ascii "=error!" +TrailNL_Msg: + .byte 13,10,0 + + +/* Main initialization */ +/***********************/ +/* DS invalid, ES==CS */ +InitContinueTop: + outchar ':' + + pushw %cs + cli + popw %ss + movw $1*1024,%sp /* Allocated 1 KB */ + sti + + movw $HelloMsg-START,%si + call PrintString + +/* now install our SniffFunction0x13 sniffer */ + + xorw %ax,%ax + movw %ax,%ds + movw $0x13*4,%si + pushw %cs + popw %es + movw $OrigVector0x13-START,%di + pushw %si + movw $SniffFunction0x13-START,%ax + cld + cli + movsw + movsw + popw %di /* = $0x13*4 */ + pushw %ds + popw %es /* = null */ + stosw /* $SniffFunction0x13-START */ + pushw %cs + popw %ax + stosw + movw $0x18*4,%di /* ROM basic - failed boot */ + movw $SniffFunction0x18-START,%ax + stosw + pushw %cs + popw %ax + stosw + sti + /* we WANT DS left with 0x0000 */ + /* we WANT ES left with 0x0000 */ + +/* and give the system control to disk=0x80/masterboot */ + movw $0x0201,%ax /* READ16 1 sector */ + movw $0x7C00,%bx /* buffer=ES:BX= 0x0000:0x7C00 */ + pushw %ds + pushw %bx /* BX/DS on stack for later 'lret', S=2, prepared for far ret */ +/* Interface to retry-capable INT13, set everything except CX */ +/* function may destroy DS value! */ +ReadSectors: + /* These two numbers get remapped to: BACKUP_SECTOR */ + movw $0x0080,%dx /* Head 0, Drive 0x80 */ + movw $0x0001,%cx /* Cylinder 0, Sector 1 */ + int $0x13 + jnc PassControl + pushw %dx /* save drive for resetting the controller */ + movw $SF13_02_Err_Msg-START,%si + call PrintString + movb $0x00,%ah /* reset controller - FDC or HDC */ + popw %dx /* restore the drive */ + int $0x13 + jmp ReadSectors + +PassControl: + cmpw $0xAA55,%es:(0x7C00+0x1FE) /* 0x55,0xAA */ + movw $BadSignatureMsg-START,%si + jne PrintFatal + cli /* IMPORTANT: Boot sectors must be run with CLI! */ + lret /* lret to 0x0000:0x7C00 */ + +SniffFunction0x18: + movw $Interrupt0x18Msg-START,%si /* %ds gets fixed in PrintFatal */ +/* fallthru */ +PrintFatal: + call PrintString +PrintFatal_dead: + jmp PrintFatal_dead + + +/**************************************************************/ +/* Section for INT13 sniffing */ +/* THIS point may start to be after 0x200 boundary */ +/**************************************************************/ + +SF13_not02: + cmpb $0x41,%ah /* presence32 */ + jne JumpVector0x13popa + cmpw $0x55AA,%bx + jne JumpVector0x13popa + stc + jmp SF13_leave + +JumpVector0x13popa: + popALL + popw %ds + incw %sp + incw %sp /* trash discarded */ + incw %sp + incw %sp /* original %ax discarded */ + popw %dx +JumpVector0x13: + .byte 0xEA /* ljmp */ +OrigVector0x13: + .skip 4 + + +SniffFunction0x13: + pushw %dx /* original %dx */ + pushw %ax /* original %ax */ + pushw %ax /* trash */ + pushw %ds + pushALL + +#if 0 + pushw %cx + pushw %dx + xorw %cx,%cx + movw $0x1,%dx +wait0: loopw wait0 + decw %dx + jnz wait0 + popw %dx + popw %cx +#endif + + cmpb $0x02,%ah /* read16 */ + jne SF13_not02 +SF13_do02_retry: + +#if 0 + pushw %cx + pushw %dx + xorw %cx,%cx + movw $0x400,%dx +wait1: loopw wait1 + decw %dx + jnz wait1 + popw %dx + popw %cx +#endif + + call CallVector0x13 + jnc SF13_selfcheck + movw $SF13_02_Err_Msg-START,%si + pushw %dx + call PrintString + popw %dx + test $0x80,%dl + jz SF13_leave /* just a floppy? */ + test $0x7E,%dl + jnz SF13_leave /* 0x82+ disk? It may be correct unsuccessful read. */ + pushw %bp + movw %sp,%bp + xorb $0x01,/*%dl:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/(%bp) +SF13_do02_retry_popw_bp: + popw %bp + jmp SF13_do02_retry + +/* Prevent: Error 17 + * as we must hide ourselves to let read GRUB itself frmo the masterboot. + */ +SF13_selfcheck: + test $0x80,%dl + jz SF13_leave /* just a floppy? */ + test $0x7E,%dl + jnz SF13_leave /* 0x82+ disk? It may be correct unsuccessful read. */ + cmpw $0x0001,%cx /* Cylinder 0, Sector 1 ? */ + jne SF13_leave_zero + cmpb $0x00,%dh /* Head 0 ? */ + jne SF13_leave_zero + movb $BACKUP_SECTOR/63,%dh + movw $1+(BACKUP_SECTOR%63),%cx +SF13_self_retry: + movw $0x0201,%ax + CallJumpVector0x13 + jnc SF13_self_ok + xorb $0x01,%dl + jmp SF13_self_retry + +SF13_self_ok: + pushw %bp + movw %sp,%bp + andb $0xFE,%ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/+2/*orig-%ax*/+2/*orig-%dx*/+4/*ret-seg:offs*/(%bp) /* flags; clear CF */ + popw %bp + +SF13_leave_zero: +#if 0 + pushw %bp + movw %sp,%bp + movb /*%al:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/+2/*%cx*/+2/*%bx*/(%bp),%al /* count */ + movw /*%cx:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/(%bp),%cx /* cylinder, sector */ + cmpb $BACKUP_SECTOR/63,/*%dh:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+1/*%dl*/(%bp) /* head */ + popw %bp + jne SF13_leave +SF13_leave_zero_loop: + andb %al,%al + jz SF13_leave + cmpw $1+(BACKUP_SECTOR%63),%cx + je SF13_leave_zero_found + incw %cx + addw $0x200,%bx + decb %al /* --count */ + jmp SF13_leave_zero_loop + +SF13_leave_zero_found: + movw %bx,%di + movw $0x200/2,%cx + xorw %ax,%ax + rep + stosw +#endif +SF13_leave: + popALL + popw %ds + incw %sp + incw %sp /* trash discarded */ + incw %sp + incw %sp /* original %ax discarded */ + popw %dx + iret + +CallVector0x13: + popw %ax /* return address */ + pushw %bp + movw %sp,%bp + movw %ax,%ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/(%bp) /* store %ax to 'trash' */ + movw %ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/(%bp),%ax /* restore original %ax */ + movw %ax,%ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/+2/*%cx*/+2/*%bx*/(%bp) /* rewrite from original %ax */ + popw %bp + popALL + popw %ds + CallJumpVector0x13 + pushw %ds + pushALL /* stack is back to normal NOW */ + pushw %bp /* trash - just to prepare return address16 */ + pushw %ax + pushw %bp + movw %sp,%bp + movw %ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/(%bp),%ax + movw %ax,%ss:2/*%bp*/+2/*ax*/(%bp) + pushf + pop %ax + movw %ax,%ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/+2/*orig-%ax*/+2/*orig-%dx*/+4/*ret-seg:offs*/(%bp) + popw %bp + popw %ax + ret /* to prepared return16 and now will be stack in normal again */ + +/* Main upper half initialization messages */ +/*******************************************/ + +HelloMsg: +#if 0 + .ascii "BIOSautoRAID, $Id$" +#else + .ascii "BaR" +#endif + .byte 13,10 + .byte 0 +BadSignatureMsg: +#if 0 + .asciz "Disk 0x80 has invalid signature!" +#else + .asciz "bs" +#endif + + +/* Interrupt sniffing messages */ +/*******************************/ + +Interrupt0x18Msg: +#if 0 + .asciz "Interrupt 0x18 - Failed boot!" +#else + .asciz "18" +#endif + + +/**************************************************************/ +/* Final sector signature */ +/**************************************************************/ + + MYORG(MAX_BOOT_SIZE) + /* Partition table */ + + MYORG(0x1FE) + .byte 0x55,0xAA + + +/* vi:ts=8:sw=8 + */ diff --git a/biosautoraid.pl b/biosautoraid.pl new file mode 100755 index 0000000..3dd40cd --- /dev/null +++ b/biosautoraid.pl @@ -0,0 +1,133 @@ +#! /usr/bin/perl +use strict; +use warnings; +use bytes; +use Getopt::Long; +use Fcntl qw(SEEK_SET); + + +sub signature($$$$;$) +{ +my($hay,$hay_filename,$offset,$needle,$msg)=@_; + + die if length($needle)%1; + my $len_bytes=length($needle)/2; + substr($hay,$offset,$len_bytes) eq pack("H*",$needle) + or die "\"$hay_filename\" error reading signature 0x$needle @".sprintf("0x%X",$offset) + .(!$msg ? "" : "; $msg")."\n"; +} + +my $BACKUP_SECTOR_START=63; +my $MAX_BOOT_SIZE=0x1b6; # LILO: leave some space for NT's and DR DOS' dirty + + +my $bin_filename="./biosautoraid.bin"; +my $opt_install; +my $opt_uninstall; +my $options_error=!GetOptions( + "bin=s" ,\$bin_filename, + "i|install" ,\$opt_install, + "u|uninstall",\$opt_uninstall, + ); +local *BIN; +open BIN,$bin_filename or die "open \"$bin_filename\": $!"; +my $bin=do { local $/; ; } or die "read \"$bin_filename\": $!"; +close BIN or die "close \"$bin_filename\": $!"; + +my $bin_len=length($bin); +$bin_len>0 && !($bin_len%0x200) or die "Invalid length of \"$bin_filename\": $bin_len"; +my $bin_short=($bin_len==0x200); # => no 0xBEEF + +signature $bin,$bin_filename,0x1FE ,"55AA"; +substr($bin,$MAX_BOOT_SIZE,0x1FE-$MAX_BOOT_SIZE)=~/^\x00*$/s or die "No empty magic+partitiontable: $bin_filename"; + +if (substr($bin,3,8) eq "BIOSRAID") { + signature $bin,$bin_filename,0x03 ,unpack("H*","BIOSRAID"); + signature $bin,$bin_filename,0x43 ,"5E81A2".sprintf("%X",$BACKUP_SECTOR_START); + signature $bin,$bin_filename,$bin_len-2,"BEEF" if !$bin_short; + } +else { + signature $bin,$bin_filename,0x03 ,unpack("H*","BIOSRAI2") + .sprintf("%X%X",$BACKUP_SECTOR_START,$MAX_BOOT_SIZE-0x100); + } + +my $all_ok; +END { + warn "Syntax: $0 [--bin=] [{-i|--install|-u|--uninstall} ]" if !$all_ok; + } + +if (!@ARGV && !$options_error) { + print "OK, \"$bin_filename\" checked.\n"; + $all_ok=1; + exit 0; + } + +die "Type -i|--install or -u|--uninstall" if (!$opt_install && !$opt_uninstall) || $options_error; +die "Both -i|--install and -u|--uninstall forbidden together" if $opt_install && $opt_uninstall; + +@ARGV<=1 or die; +my $device_filename=$ARGV[0]; + +local *DEVICE; +open DEVICE,"+<".$device_filename or die "open \"$device_filename\": $!"; + +my $backup_offset=$BACKUP_SECTOR_START*0x200; + +sysseek DEVICE,0,SEEK_SET or die "Error seeking $device_filename"; +my $master; +$bin_len==sysread DEVICE,$master,$bin_len or die "read \"$device_filename\": $!"; +length($master)==$bin_len or die "read \"$device_filename\": ".length($master)."!=$bin_len"; +signature $master,$device_filename,0x1FE,"55AA"; + +sysseek DEVICE,$backup_offset,SEEK_SET or die "Error seeking $device_filename"; +my $backup; +$bin_len==sysread DEVICE,$backup,$bin_len or die "read \"$device_filename\": $!"; +length($backup)==$bin_len or die "read \"$device_filename\": ".length($backup)."!=$bin_len"; + +my $zeroes="\x00"x$bin_len; +die if length($zeroes)!=$bin_len; + +$bin=substr($bin,0,$MAX_BOOT_SIZE).substr($master,$MAX_BOOT_SIZE,0x1FE-$MAX_BOOT_SIZE).substr($bin,0x1FE); + +my $installed=substr($master,0x03,7) eq "BIOSRAI"; +print "Already instaled? ".($installed ? "YES" : "NO")."\n"; + +die "Nothing to uninstall!\n" if $opt_uninstall && !$installed; + +if ($installed) { + signature $master,$device_filename,$bin_len-2,"BEEF","Different installed SECTOR_LEN?" if !$bin_short; + signature $master,$device_filename,0x03 ,unpack("H*","BIOSRAI"); + signature $master,$device_filename,0x43 ,"5E81A2".sprintf("%X",$BACKUP_SECTOR_START) if !$bin_short; + signature $backup,"backup",0x1FE,"55AA"; + } +if ($opt_install) { + if (!$installed) { + if ($backup ne $zeroes) { + # Permit different DOS-volume area and 0x1FC..0x1FD bytes. + die "Sensitive bytes at backup sectors" if !(1 + && (0 + || substr($backup,0x200) eq substr($zeroes,0x200) + || (substr($backup,$bin_len-2) eq pack("H*","BEEF") && !$bin_short) + ) + && substr($backup,0,0x03) eq substr($master,0,0x03) + && substr($backup,0x5A,$MAX_BOOT_SIZE-0x5A) eq substr($master,0x5A,$MAX_BOOT_SIZE-0x5A) + ); + warn "WARNING: Dropping obsolete (but similiar) backup! Use --uninstall next time.\n"; + } + sysseek DEVICE,$backup_offset,SEEK_SET or die "Error seeking $device_filename"; + $bin_len==syswrite DEVICE,$master or die "Error backing up the master"; + } + sysseek DEVICE,0,SEEK_SET or die "Error seeking $device_filename"; + $bin_len==syswrite DEVICE,$bin or die "Error writing new master of BIOSautoRAID"; + } +if ($opt_uninstall) { + sysseek DEVICE,0,SEEK_SET or die "Error seeking $device_filename"; + $bin_len==syswrite DEVICE,$backup or die "Error writing backup back to the master"; + sysseek DEVICE,$backup_offset,SEEK_SET or die "Error seeking $device_filename"; + $bin_len==syswrite DEVICE,$zeroes or die "Error clearing the backup area"; + } + +close DEVICE or die "close \"$device_filename\": $!"; + +print "OK; ".($opt_install ? ($installed ? "re" : "")."installed" : "uninstalled")."\n"; +$all_ok=1;