+/*
+ * $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
+ */