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