--- /dev/null
+/*
+ * $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
+ */
--- /dev/null
+#! /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 $/; <BIN>; } 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=<biosautoraid.bin>] [{-i|--install|-u|--uninstall} <device>]" 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;