Comment: Provide better Int13Sniff URL.
[biosautoraid.git] / biosautoraid.S
1 /*
2  * $Id$
3  *
4  * Automatically retry all BIOS reads 0x80<->0x81 (and if (drive&0x80) drive^=1; in genral)
5  *
6  * Derived from:
7  *      http://www.jankratochvil.net/project/int13sniff/
8  */
9
10
11 /* !!!  All defines below must be COMMENTED-OUT !
12  * !!!  Define to value 0 has no effect.
13  */
14
15 /* Reduce size by omitting DOS-boot header signature to fit in 512 bytes.
16  * Cylinder 0 is requierd, sectors per track == 63 assumed!
17  * This constant is counted from 0 !!!
18  */
19 #define BACKUP_SECTOR 63
20
21 /* Reduce size by omitting DOS-boot header signature to fit in 512 bytes.
22  */
23 #define STRIP_BOOT_HEADER 1
24
25 /* Reduce size by omitting INT 0x18 handler.
26  */
27 #define STRIP_INT18 1
28
29 /* Maintainers: Disable .org macroinstructions: ONLY FOR compilation tuning!
30  *  - image produced doen't have any functionality!
31 #define DISABLE_ORG 1
32  */
33
34 /* Internal defines */
35 #define MEM_KBYTES    0x413     /* BIOS variable */
36
37 #define MAX_BOOT_SIZE_100  0xb6 /* LILO: leave some space for NT's and DR DOS' dirty */
38 #define MAX_BOOT_SIZE (MAX_BOOT_SIZE_100+0x100)
39
40
41 /* Macros: */
42
43         .macro  outchar char
44         movw    $0x0E00 | \char,%ax
45         movw    $7,%bx
46         int     $0x10
47         .endm
48
49 #ifdef DISABLE_ORG
50 #define MYORG(offset)
51 #else
52 #define MYORG(offset) .org (offset) + START             /* "+ START" MUST be on the end of line - WHY?!? */
53 #endif
54
55         .macro  pushALL
56         pushw   %ax
57         pushw   %bx
58         pushw   %cx
59         pushw   %dx
60         pushw   %si
61         pushw   %di
62         pushw   %bp
63         .endm
64
65         .macro  popALL
66         popw    %bp
67         popw    %di
68         popw    %si
69         popw    %dx
70         popw    %cx
71         popw    %bx
72         popw    %ax
73         .endm
74
75 #define PUSHALL_SIZE (7*2)
76 #define PUSHALL_SI   ((1/*%bp*/+1/*%di*/)*2)
77
78         .macro  CallJumpVector0x13
79         pushf                   /* create 'lret' stack by this pushf... */
80         pushw   %cs             /* ...this segment... */
81         call    JumpVector0x13  /* ...and this return address */
82         .endm
83
84
85
86 /* Code starts here */
87 /********************/
88
89         .arch   i8086,nojumps
90         .code16
91         .text
92         .globl  _start
93 _start:
94
95 /* init stack */
96 START:
97         cli                     /* just a paranoia, shouldn't be needed */
98         jmp     InitRawStack    /* We don't want to have 0x90 on offset 2 (one of recognization rules by DOS) */
99         .org    START+0x03
100
101         .macro  places offset length string
102         .org    (\offset) + START
103         .ascii  "\string"
104         .org    (\offset) + (\length) + START           /* we can't check whether it isn't too short :-(  */
105         .endm
106         .macro  placex offset length bytes
107         .org    (\offset) + START
108         .byte   \bytes
109         .org    (\offset) + (\length) + START           /* we can't check whether it isn't too short :-(  */
110         .endm
111
112 /* We rather supply empty (=zeroed) FAT filesystem table
113  */
114 #ifndef STRIP_BOOT_HEADER
115         places  0x03,8,"BIOSRAID"               /* OEM ID */
116         placex  0x43,3,"0x5E,0x81,0xA2"         /* Volume Serial Number: 5E81A2?? as "SERIAL??" */
117         placex  0x43+3,1,BACKUP_SECTOR          /* Volume Serial Number: 5E81A23F as "SERIAL??" */
118         places  0x47,11,"BIOSauRAID\0"          /* Volume Label */
119         places  0x52,8,"BootOnly"               /* Filesystem ID */
120 #else
121         places  0x03,8,"BIOSRAI2"               /* OEM ID */
122         placex  0x03+8,1,BACKUP_SECTOR          /* Sanity checked by: biosautoraid.pl */
123         placex  0x03+9,1,MAX_BOOT_SIZE_100      /* Sanity checked by: biosautoraid.pl */
124 #endif
125
126 InitRawStack:
127 #ifndef STRIP_BOOT_HEADER
128         .org    0x5A + START
129 #endif
130
131         xorw    %ax,%ax
132         movw    %ax,%ss
133         movw    $0x7C00,%sp
134         sti
135 #if 0
136         outchar '1'
137 #endif
138         ljmp    $0x7C0/*segment*/ , $InitContinue7C0-START/*offset*/
139
140 InitContinue7C0:
141 #if 0
142         outchar '2'
143 #endif
144
145 /* move to top memory */
146         xorw    %dx,%dx         /* DX=null */
147         movw    %dx,%ds
148         movw    %ds:MEM_KBYTES,%ax
149         decw    %ax             /* Allocation size: 1KB */
150         movw    %ax,%ds:MEM_KBYTES
151         movb    $6,%cl
152         shlw    %cl,%ax
153         movw    %ax,%es
154         xorw    %di,%di         /* buffer=ES:DI */
155         movw    $0x7C00,%si
156         movw    $0x200/2,%cx
157         rep
158         movsw
159         pushw   %es
160         movw    $InitContinueTop-START,%ax
161         pushw   %ax
162         lret
163
164 PrintTrailNL:
165         movw    $TrailNL_Msg-START,%si
166         jmp     PrintString_noPref
167
168 /* String is given in SI, returns updated SI */
169 PrintString:
170         movb    $'%',%al
171         call    PrintChar
172 PrintString_noPref:
173         pushw   %cs
174         popw    %ds
175 PrintString_loop:
176         cld
177         lodsb
178         testb   %al,%al
179         jz      Return1
180         movw    $PrintString_loop-START,%bx     /* from now do just 'ret' to close the loop */
181         pushw   %bx
182 /* fallthru */
183
184 /* Character is given in AL
185  * Preserves: DS, ES, SI, DI
186  * Destroys: AX (even AL!), BX, CX, DX
187  * DS is sometimes left preserved, sometimes set to DS=CS
188  */
189 PrintChar:
190         movb    $0x0E,%ah       /* print character */
191         movw    $7,%bx
192         pushw   %ax
193         int     $0x10
194         popw    %ax
195 Return1:
196         ret
197
198
199 SF13_02_Err_Msg:
200         .ascii  "Read16"
201 SnifferErrTail_MSG:
202         .ascii  "=error!"
203 TrailNL_Msg:
204         .byte   13,10,0
205
206
207 /* Main initialization */
208 /***********************/
209 /* DS invalid, ES==CS */
210 InitContinueTop:
211 #if 0
212         outchar ':'
213 #endif
214
215         pushw   %cs
216         cli
217         popw    %ss
218         movw    $1*1024,%sp             /* Allocated 1 KB */
219         sti
220
221         movw    $HelloMsg-START,%si
222         call    PrintString
223
224 /* now install our SniffFunction0x13 sniffer */
225
226         xorw    %ax,%ax
227         movw    %ax,%ds
228         movw    $0x13*4,%si
229         pushw   %cs
230         popw    %es
231         movw    $OrigVector0x13-START,%di
232         pushw   %si
233         movw    $SniffFunction0x13-START,%ax
234         cld
235         cli
236         movsw
237         movsw
238         popw    %di     /* = $0x13*4 */
239         pushw   %ds
240         popw    %es     /* = null */
241         stosw           /* $SniffFunction0x13-START */
242         pushw   %cs
243         popw    %ax
244         stosw
245 #ifndef STRIP_INT18
246         movw    $0x18*4,%di     /* ROM basic - failed boot */
247         movw    $SniffFunction0x18-START,%ax
248         stosw
249         pushw   %cs
250         popw    %ax
251         stosw
252 #endif /* !STRIP_INT18 */
253         sti
254         /* we WANT DS left with 0x0000 */
255         /* we WANT ES left with 0x0000 */
256
257 /* and give the system control to disk=0x80/masterboot */
258         movw    $0x0201,%ax     /* READ16 1 sector */
259         movw    $0x7C00,%bx     /* buffer=ES:BX= 0x0000:0x7C00 */
260         pushw   %ds
261         pushw   %bx             /* BX/DS on stack for later 'lret', S=2, prepared for far ret */
262 /* Interface to retry-capable INT13, set everything except CX */
263 /* function may destroy DS value! */
264 ReadSectors:
265         /* These two numbers get remapped to: BACKUP_SECTOR */
266         movw    $0x0080,%dx     /* Head 0, Drive 0x80 */
267         movw    $0x0001,%cx     /* Cylinder 0, Sector 1 */
268         int     $0x13
269         jnc     PassControl
270         pushw   %dx     /* save drive for resetting the controller */
271         movw    $SF13_02_Err_Msg-START,%si
272         call    PrintString
273         movb    $0x00,%ah       /* reset controller - FDC or HDC */
274         popw    %dx             /* restore the drive */
275         int     $0x13
276         jmp     ReadSectors
277
278 PassControl:
279         cmpw    $0xAA55,%es:(0x7C00+0x1FE)              /* 0x55,0xAA */
280         movw    $BadSignatureMsg-START,%si
281         jne     PrintFatal
282         cli                     /* IMPORTANT: Boot sectors must be run with CLI! */
283         lret                    /* lret to 0x0000:0x7C00 */
284
285 #ifndef STRIP_INT18
286 SniffFunction0x18:
287         movw    $Interrupt0x18Msg-START,%si     /* %ds gets fixed in PrintFatal */
288 #endif /* !STRIP_INT18 */
289 /* fallthru */
290 PrintFatal:
291         call    PrintString
292 PrintFatal_dead:
293         jmp     PrintFatal_dead
294
295
296 /**************************************************************/
297 /* Section for INT13 sniffing                                 */
298 /* THIS point may start to be after 0x200 boundary            */
299 /**************************************************************/
300
301 SF13_not02:
302         cmpb    $0x41,%ah       /* presence32 */
303         jne     JumpVector0x13popa
304         cmpw    $0x55AA,%bx
305         jne     JumpVector0x13popa
306         stc
307         jmp     SF13_leave
308
309 JumpVector0x13popa:
310         popALL
311         popw    %ds
312         incw    %sp
313         incw    %sp     /* trash discarded */
314         incw    %sp
315         incw    %sp     /* original %ax discarded */
316         popw    %dx
317 JumpVector0x13:
318         .byte   0xEA    /* ljmp */
319 OrigVector0x13:
320         .skip   4
321
322
323 SniffFunction0x13:
324         pushw   %dx     /* original %dx */
325         pushw   %ax     /* original %ax */
326         pushw   %ax     /* trash */
327         pushw   %ds
328         pushALL
329
330 #if 0
331         pushw   %cx
332         pushw   %dx
333         xorw    %cx,%cx
334         movw    $0x1,%dx
335 wait0:  loopw   wait0
336         decw    %dx
337         jnz     wait0
338         popw    %dx
339         popw    %cx
340 #endif
341
342         cmpb    $0x02,%ah       /* read16 */
343         jne     SF13_not02
344 SF13_do02_retry:
345
346 #if 0
347         pushw   %cx
348         pushw   %dx
349         xorw    %cx,%cx
350         movw    $0x400,%dx
351 wait1:  loopw   wait1
352         decw    %dx
353         jnz     wait1
354         popw    %dx
355         popw    %cx
356 #endif
357
358         pushw   %bp
359         movw    %sp,%bp
360         movb    /*orig-%dl:*/ %ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/+2/*orig-%ax*/(%bp),%dl
361         xorb    %cs:DriveFlipFlag-START,%dl     /* %ds not yet initialized by: PrintString */
362         movb    %dl,/*%dl:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/(%bp)
363         popw    %bp
364         call    CallVector0x13
365         jnc     SF13_selfcheck
366         movw    $SF13_02_Err_Msg-START,%si
367         pushw   %dx
368         call    PrintString
369         popw    %dx
370         test    $0x80,%dl
371         jz      SF13_leave              /* just a floppy? */
372         test    $0x7E,%dl
373         jnz     SF13_leave              /* 0x82+ disk? It may be correct unsuccessful read. */
374         xorb    $0x01,%ds:DriveFlipFlag-START   /* %ds already initialized by: PrintString */
375         jmp     SF13_do02_retry
376
377 /* Prevent: Error 17
378  * as we must hide ourselves to let read GRUB itself frmo the masterboot.
379  */
380 SF13_selfcheck:
381         test    $0x80,%dl
382         jz      SF13_leave              /* just a floppy? */
383         test    $0x7E,%dl
384         jnz     SF13_leave              /* 0x82+ disk? It may be correct unsuccessful read. */
385         cmpw    $0x0001,%cx             /* Cylinder 0, Sector 1 ? */
386         jne     SF13_leave_zero
387         cmpb    $0x00,%dh               /* Head 0 ? */
388         jne     SF13_leave_zero
389         movb    $BACKUP_SECTOR/63,%dh
390         movb    $1+(BACKUP_SECTOR%63),%cl
391 SF13_self_retry:
392         pushw   %dx
393         xorb    %cs:DriveFlipFlag-START,%dl     /* %ds not yet initialized by: PrintString */
394         movw    $0x0201,%ax
395         CallJumpVector0x13
396         popw    %dx
397         jnc     SF13_self_ok
398         xorb    $0x01,%cs:DriveFlipFlag-START   /* %ds not yet initialized by: PrintString */
399         jmp     SF13_self_retry
400
401 SF13_self_ok:
402         pushw   %bp
403         movw    %sp,%bp
404         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 */
405         popw    %bp
406
407 SF13_leave_zero:
408 #if 0
409         pushw   %bp
410         movw    %sp,%bp
411         movb    /*%al:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/+2/*%cx*/+2/*%bx*/(%bp),%al    /* count */
412         movw    /*%cx:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/(%bp),%cx      /* cylinder, sector */
413         cmpb    $BACKUP_SECTOR/63,/*%dh:*/ %ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+1/*%dl*/(%bp)        /* head */
414         popw    %bp
415         jne     SF13_leave
416 SF13_leave_zero_loop:
417         andb    %al,%al
418         jz      SF13_leave
419         cmpw    $1+(BACKUP_SECTOR%63),%cx
420         je      SF13_leave_zero_found
421         incw    %cx
422         addw    $0x200,%bx
423         decb    %al                     /* --count */
424         jmp     SF13_leave_zero_loop
425
426 SF13_leave_zero_found:
427         movw    %bx,%di
428         movw    $0x200/2,%cx
429         xorw    %ax,%ax
430         rep
431         stosw
432 #endif
433 SF13_leave:
434         popALL
435         popw    %ds
436         incw    %sp
437         incw    %sp     /* trash discarded */
438         incw    %sp
439         incw    %sp     /* original %ax discarded */
440         popw    %dx
441         iret
442
443 CallVector0x13:
444         popw    %ax     /* return address */
445         pushw   %bp
446         movw    %sp,%bp
447         movw    %ax,%ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/(%bp)     /* store %ax to 'trash' */
448         movw    %ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/(%bp),%ax  /* restore original %ax */
449         movw    %ax,%ss:2/*%bp*/+2/*%bp*/+2/*%di*/+2/*%si*/+2/*%dx*/+2/*%cx*/+2/*%bx*/(%bp)     /* rewrite from original %ax */
450         popw    %bp
451         popALL
452         popw    %ds
453         CallJumpVector0x13
454         pushw   %ds
455         pushALL                 /* stack is back to normal NOW */
456         pushw   %bp             /* trash - just to prepare return address16 */
457         pushw   %ax
458         pushw   %bp
459         movw    %sp,%bp
460         movw    %ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/(%bp),%ax
461         movw    %ax,%ss:2/*%bp*/+2/*ax*/(%bp)
462         pushf
463         pop     %ax
464         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)
465         popw    %bp
466         popw    %ax
467         ret                     /* to prepared return16 and now will be stack in normal again */
468
469 /* Main upper half initialization messages */
470 /*******************************************/
471
472 HelloMsg:
473 #if 0
474         .ascii  "BIOSautoRAID, $Id$"
475 #else
476         .ascii  "BaR"
477 #endif
478         .byte   13,10
479 DriveFlipFlag:
480         .byte   0
481 BadSignatureMsg:
482 #if 0
483         .asciz  "Disk 0x80 has invalid signature!"
484 #else
485         .asciz  "bs"
486 #endif
487
488
489 /* Interrupt sniffing messages */
490 /*******************************/
491
492 #ifndef STRIP_INT18
493 Interrupt0x18Msg:
494 #if 0
495         .asciz  "Interrupt 0x18 - Failed boot!"
496 #else
497         .asciz  "18"
498 #endif
499 #endif /* !STRIP_INT18 */
500
501
502 /**************************************************************/
503 /* Final sector signature                                     */
504 /**************************************************************/
505
506         MYORG(MAX_BOOT_SIZE)
507         /* Partition table */
508
509         MYORG(0x1FE)
510         .byte   0x55,0xAA
511
512
513 /* vi:ts=8:sw=8
514  */