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