debconf translation NL update
[rrq/maintain_lilo.git] / src / chain.S
1 ;  chain.S  -  LILO boot chainer 
2 ;
3 ; Copyright 1992-1998 Werner Almesberger.
4 ; Copyright 1999-2004 John Coffman.
5 ; All rights reserved.
6 ;
7 ; Licensed under the terms contained in the file 'COPYING' in the 
8 ; source directory.
9 ;
10
11 #define LILO_ASM
12 #include "lilo.h"
13 get common.s            /* as86 "include" will bypass the CPP */
14
15 ; for debugging, set the EBDA size in Kilobytes; e.g., 64
16 #define EBDA 0
17
18 #define REVERSE_DL 1
19
20 #if defined(LCF_SOLO_CHAIN) && !defined(DOS_D)
21
22 #ifndef DOS_D
23 #define DOS_D
24 #endif
25
26 #ifndef CHECK
27 #define CHECK
28 #endif
29
30 #endif          /* LCF_SOLO_CHAIN */
31
32
33 #if VERSION_MINOR >= 50
34 #define DEBUG_NEW
35 #endif
36
37         .text
38
39         .globl  _main
40         .org    0
41
42 _main:  cld                     ! make sure !!!
43         jmp     start
44
45         
46         .org    6
47
48         .ascii  "LILO"          ! signature
49
50         .word   STAGE_CHAIN
51         .word   VERSION
52
53 offset: .word   0
54
55 ! the byte "drive" is filled in by the installer & updated by the second stage 
56
57 drive:  .byte   0                       ! drive, 0x80, 0x81
58         .byte   0                       ! head, always zero
59
60 hint:   .word   drvmap                  ! pointer to drive map
61
62 ptable: .blkw   0x20                    ! partition table to preload
63
64 devmap: .word   0,0                     ! device map filled in by second.S
65
66 cmd:    .word   0,0                     ! command line to pass on
67
68 ; ES:DI contains a pointer to the command line passed from second-stage
69
70 start:
71         xor     bx,bx                   ! set SS:SP to 0:7C00
72         mov     ss,bx
73         mov     sp,#BOOTSEG*16          ! #0x7C00
74         mov     bp,sp                   ! address from BP
75 #if EBDA
76         push    #0x40
77         pop     ds
78         mov     word ptr [0x13],#640-EBDA       ; simulate EBDA in Kilobytes
79 #endif
80         push    cs
81         pop     ds
82
83 #ifdef DEBUG_NEW
84         push    bp
85
86         push    es
87         pop     ds
88         mov     si,di
89         call    say
90
91         push    cs
92         pop     ds
93         mov     si,#crlf
94         call    say
95
96         call    bd1
97         .ascii  "Boot drive 0x"
98         .byte   0
99 bd1:    pop     si
100         call    say
101         mov     al,drive
102         call    bout
103         mov     si,#crlf
104         call    say
105
106         pop     bp
107 #endif
108
109         mov     al,#0x3D                ! '=' sign
110         mov     cx,#-1
111         repne
112           scasb                         ! scan for =
113 srch:   seg es
114           mov   al,(di)
115         inc     di
116         cmp     al,#0x20                ! test for space
117         ja      srch
118 ; real command line if AL==space, no command line if NUL
119         jb      nocmd
120         mov     [cmd],di
121         mov     [cmd+2],es
122 nocmd:
123
124 ;
125 ; Account for any drive mappings being used by the Second Stage
126 ;
127         les     di,[parC_devmap]        ! second stage translate table
128                                         ! this was set by the second stage loader
129 #if defined DEBUG_NEW
130         mov     ax,es
131         call    wout
132         mov     al,#0x20
133         call    cout
134         mov     ax,di
135         call    wout
136         mov     si,#crlf
137         call    say
138
139         mov     bx,di
140         call    dump_drvmap
141 #endif
142
143         call    install_map             ! install it
144
145
146 ; but first, process the two 0xFFFF drive-map records for "master-boot"
147 ;
148         mov     si,#drvmap              ! our created drive map
149         cmp     WORD (si),#-1           ! test for "master-boot"
150         jne     noswap
151         mov     ah,[drive]              ! boot drive
152         mov     al,(si+3)               ! possible "boot-as="
153         cmp     al,#-1                  ! test for master
154         jne     boot_as
155 ! make AL the master drive (0 or 80)
156         mov     al,ah
157         and     al,#0x80                ! AL is master drive 0 or 80
158 boot_as:
159         mov     (si),ax         ! 80 -> boot
160         xchg    ah,al
161         mov     (si+2),ax               ! boot -> 80
162
163         cmp     ah,al                   ! are they the same
164         jne     domerge
165         add     si,#4                   ! skip a "no-translation"
166         mov     byte (si-1),#-1         ! clear any boot-as
167 noswap:
168 domerge:
169
170         mov     [devmap],si     ! save updated value
171
172
173 ;**************************************
174         push    ss
175         pop     es
176
177         mov     cx,#SECTOR_SIZE/2
178 mtmp = SETUPSECS-1                      ! broken math ...
179         mov     si,#mtmp*SECTOR_SIZE
180 #ifdef DEBUG_NEW
181         mov     di,#boot_sector
182         cmp     si,di
183         ja      use_setupsecs_m_1
184         mov     si,di
185 use_setupsecs_m_1:
186 #endif
187         mov     di,bp                   ! #0x7C00
188         rep
189           movsw
190 #ifdef DOS_D
191 #ifdef CHECK
192         mov     si,#BOOTSEG*16+0x24     ; address of first byte to test
193
194         cmp     byte (bp+0x15),#0xf8            ; check media descriptor
195         jne     ck_failed
196
197         seg     es
198           lodsb
199         cmp     al,#0x80                ; check range of device codes
200         jb      ck_failed
201         cmp     al,#0x8f
202         ja      ck_failed
203
204         seg     es
205           lodsb
206         or      al,al                   ; check hi-byte is empty
207         jnz     ck_failed
208
209         seg     es
210           lodsb
211         cmp     al,#0x29                ; I do not know what this byte means
212         je      ck_okay
213         cmp     al,#0x28                ; HPFS marker
214         jne     ck_failed
215
216 ck_okay:
217         lea     si,(si+4)               ; address of vol label & fs type
218         mov     cx,#11                  ; volume label (11)
219 ck_next:
220         seg     es
221           lodsb
222         or      al,al
223         js      ck_failed               ; not alphabetic if >= 0x80
224         jz      ck_loop                 ; NUL allowed for HPFS
225         cmp     al,#0x20
226         jb      ck_failed               ; not alphabetic if < SPACE
227 ck_loop:
228         loop    ck_next
229
230         mov     cx,#8                   ; check Filesystem type
231 ck_fstype:
232         seg     es
233           lodsb
234         or      al,al                   ; not alphabetic if >= 0x80
235         js      ck_failed
236         cmp     al,#0x20                ; not alphabetic if < SPACE
237         jb      ck_failed
238         loop    ck_fstype
239
240 #endif
241 dos4:
242
243         call    revmap1
244
245         mov     (bp+0x24),dx            ! fill in 0x24 and 0x25
246         mov     si,offset
247         mov     edx,ptable+8(si)
248         mov     (bp+0x1C),edx
249
250 #ifdef DEBUG_NEW
251         mov     si,#update
252         jmp     ck_say   
253 ck_failed:
254         mov     si,#no_update
255 ck_say:
256         call    say
257 #else
258 ck_failed:
259 #endif
260
261 #endif
262         mov     cx,#0x20                ! move partition table
263         mov     si,#ptable
264         mov     di,#PART_TABLE
265         rep
266         movsw
267                                         ! mess with the partition table
268 #if defined(LCF_REWRITE_TABLE) && !defined(LCF_READONLY)
269         mov     si,#prtmap              ! get partition table change rules
270 prtclp: lodsw                           ! bios == 0 indicates end
271         or      al,al
272         jz      pmend                   ! at end -> quit
273         cmp     al,cache                ! already in cache ?
274         je      incache                 ! yes -> no loading required
275         push    ax                      ! save table data
276         call    flush                   ! flush the cache
277         pop     ax
278         push    ax
279         mov     cache,al                ! remember drive in cache
280 #if 0
281         cmp     al,drive                ! boot drive ?
282 #else
283         call    revmap1
284         cmp     al,dl
285 #endif
286         jne     noc                     ! no -> load into scratch area
287         xor     ax,ax                   ! load at 0000:0600
288         mov     bx,#PARTS_LOAD
289         jmp     loadit
290
291 pmend:  call    flush                   ! flush table
292         br      nopp                    ! and proceed
293
294 noc:    mov     ax,ds
295         mov     bx,#PARTS_SCR           ! scratch area  0000:0800
296 loadit: mov     es,ax                   ! set up pointers and remember them
297         mov     ces,ax
298         mov     cbx,bx
299         mov     ax,#0x201               ! load partition table, one sector
300         mov     dx,cache                ! drive from cache (DH = 0)
301         mov     cx,#1
302 #ifdef DEBUG_NEW
303         pusha
304         mov     al,dl                   ! dump device code
305         call    bout
306         mov     si,#msg_load            ! say loading
307         call    say
308         popa
309 #endif
310         int     0x13                    ! load it
311         jc      wrfail                  ! error -> abort
312         pop     ax                      ! get BIOS and offset
313 incache:les     bx,cbx                  ! load pointer
314         add     bx,#PART_TABLE_OFFSET   ! move to partition table
315         add     bl,ah                   ! offset is always in [0x1be,0x1fd]
316         lodsw                           ! see what we need to do
317         seg     es                      ! match ?
318         cmp     byte ptr (bx),al
319         jne     nocng                   ! no -> do not change
320         seg     es                      ! change
321         mov     byte ptr (bx),ah
322         mov     byte ptr dirty,#1       ! mark as dirty
323 nocng:  br      prtclp                  ! next one
324
325 flush:  test    byte ptr dirty,#1       ! dirty ?
326         jz      noflush                 ! no -> do not write
327         mov     ax,#0x301               ! write one sector
328         mov     dx,cache                ! get the drive
329         or      dl,dl                   ! nothing cached ?
330         jz      noflush                 ! no -> do not flush
331         les     bx,cbx                  ! reload pointer
332 #ifdef DEBUG_NEW
333         pusha
334         mov     al,dl                   ! dump device code
335         call    bout
336         mov     si,#msg_write           ! say writing
337         call    say
338         popa
339 #endif
340         int     0x13                    ! write ...
341         jc      wrfail                  ! argl
342 noflush:ret
343 wrfail: mov     si,#failmsg             ! complain
344         call    say
345 #if 0
346         mov     ax,#FIRSTSEG            ! try to restart LILO
347         jmpi    #GO,FIRSTSEG
348 #else
349         xor     dx,dx                   ! zap the device code
350         jmpi    FIRSTSEG*16,0           ! try to restart at 0000:7c00
351 #endif
352 cache:  .byte   0                       ! drive, 0 means not cached
353         .byte   0                       ! head, always 0
354 cbx:    .blkw   1
355 ces:    .blkw   1
356 dirty:  .byte   0
357
358 #endif
359
360 ; reverse drive mapping
361 ;       uses AX
362 ;       updates DL
363 ;
364 revmap1:
365         push    si
366         mov     dx,drive        ; get drive/head pair
367         mov     si,#drvmap
368 rev0:   lodsw                   ; get to, from pair
369         or      ax,ax           ; test for end
370         jz      rev9            ; done
371         cmp     ah,dl           ; booting from "to"
372         jne     rev0            ; loop if not
373         mov     dl,al           ; substitute the "from"
374 rev9:   pop     si              ; restore SI
375         ret
376
377 nopp:
378 #if 0
379         mov     ax,drvmap               ! need to install mapper ?
380         or      ax,ax
381         jz      noimap                  ! no -> go on
382         call    swap13
383 noimap:
384 #else
385         mov     di,[devmap]     ! get drive map pointer
386         cmp     word (di),#0
387         je      noimap
388         push    cs
389         pop     es              ; ES:DI points at the current map
390         call    install_map
391 noimap:
392 #endif
393
394
395 #if REVERSE_DL
396         call    revmap1
397 #else
398         mov     dx,drive                ! initialize DX (drive and head)
399 #endif
400         mov     si,offset               ! DS:SI and ES:SI point to the partition
401         add     si,#PART_TABLE
402 #ifdef DEBUG_NEW
403         pusha
404
405         mov     cx,# 4<<4               ; delay 4 seconds
406         xor     dx,dx
407         mov     ah,# 0x86
408         int     0x15                    ! Delay 6 seconds
409 #ifdef DEBUG_CONTINUE
410         jnc     delayed
411
412         mov     si,#msg_cont            ! Hit any key ...
413         call    say
414         xor     ax,ax
415         int     0x16    ! AH==0, get key
416 delayed:
417 #endif
418
419         popa
420 #endif
421
422         xor     ax,ax                   ! set DS and ES to zero
423         mov     ds,ax
424         mov     es,ax
425         mov     bx,#BOOTSEG*16
426         
427 ;;;;    mov     ss,ax                   ! on all processors since the 186
428         mov     sp,bx                   ! these instructions are locked
429         
430 #ifdef LCF_COHERENT
431         mov     (si),dl                 ! yes, put it in the partition table
432 #endif
433         mov     bp,si                   ! BP==SI flags hard disk boot
434         push    ax
435         push    bx
436         seg ss
437         cmp     byte ptr (bx+par1_cli),#0xFA    ! first.S starts with CLI
438         je      try_sig
439         cmp     byte ptr (bx+par1_cli),#0xEB    ! short jump?
440         jne     gotoit
441         push    ax
442         mov     al,(bx+par1_cli+1)              ! get offset
443         cbw
444         inc     ax
445         inc     ax
446         add     bx,ax                   ! test relocated record
447         pop     ax
448         cmp     byte ptr (bx+par1_cli),#0xFA    ! first.S starts with CLI
449         jne     gotoit                  ! not LILO if no CLI
450 try_sig:
451         seg ss
452           cmp   dword ptr (bx+par1_signature),#EX_MAG_HL
453         jne     gotoit          ! LILO signature required for command line
454         seg cs
455           cmp   dword ptr [cmd],#0
456         je      gotoit
457
458 ;  pass on a command line
459         seg cs
460           les   bx,[cmd]
461         lea     si,(bx-4)
462         seg es
463           mov   dword ptr (si),#EX_MAG_HL
464         mov     dh,dl
465         mov     dl,#EX_DL_MAG
466 gotoit:
467         retf
468
469
470 #if defined(LCF_REWRITE_TABLE) || defined(DEBUG_NEW)
471
472 ! Display a NUL-terminated string on the console
473 !       DS:SI points at the string
474 !
475 say:    push    ax
476         push    bx              ! save BX
477 say_2:  lodsb                   ! get byte
478         or      al,al           ! NUL ?
479         jz      aret            ! yes -> done
480         mov     ah,#14          ! display, tty-style
481         mov     bx,#0007
482         int     0x10
483         jmp     say_2           ! next one
484 aret:   pop     bx              ! restore
485         pop     ax
486         ret                     ! done
487
488 failmsg:.ascii  "Rewrite error."
489         .byte   13,10,0
490
491 #endif
492
493 ;**************************************
494
495
496 ; Merge the contents of two drive maps
497 ;
498 ;       First drive map encountered:    DS:SI
499 ;       Second drive map encountered:   ES:DI
500 ;       Output drive map:               DS:BX
501 ;
502 ; The output drive coincides with the First drive map
503 ;
504 ;       Enter with  DS != CS
505 ;
506 ;
507 ;       
508 drive_map_merge:
509         pusha                           ! save all the registers
510
511 ;
512 ; this is the guts of the loop to merge the records
513 ;
514 process:
515         lodsw                           ! get drive mapping
516         or      ax,ax
517         jz      copy
518
519         push    di
520         jmp     nextone1
521 nextone:
522         inc     di
523         inc     di
524 nextone1:
525         seg es
526           cmp   word (di),#0
527         je      atend
528
529         seg es
530           cmp   (di),ah
531         jne     nextone
532
533         seg es
534           mov   ah,(di+1)               ! do the translation
535         seg es
536           mov   word (di),#-1           ! wipe out entry
537 atend:
538         cmp     ah,al                   ! remove null translation
539         je      nostore
540         mov     (bx),ax
541         inc     bx
542         inc     bx
543 nostore:
544         pop     di
545         jmp     process
546
547 ; finished merge, copy the rest from the source
548 copy:
549         seg es
550           mov   ax,(di)                 !
551         inc     di
552         inc     di
553
554         inc     ax
555         jz      copy                    ! it was -1, skip it
556
557         dec     ax
558         mov     (bx),ax                 ! store value or end marker
559
560         jz      alldone                 ! it was 0, end marker
561
562         inc     bx
563         inc     bx
564         jmp     copy
565
566
567 alldone:
568         popa                    ! restore all that we saved
569         ret
570
571 ; end of drive_map_merge
572
573 ;**************************************
574
575 ; Install a drive swapper with a null drive map
576 ;
577 ;       Enter with:
578 ;               DS == CS, SS == 0000
579 ;
580 ;       Exit with:
581 ;               ES:DI points at the null device map
582 ;
583 ;               EAX is trashed
584 ;               All other registers preserved
585 ;
586 ;
587 swap13_null:
588         push    cx
589         push    si
590 #ifdef DEBUG_NEW
591         call    sn11
592         .asciz  "Installing Drive Swapper\r\n"
593 sn11:   pop     si
594         call    say
595 #endif
596         seg ss
597           dec   word [0x413]    ; allocate 1k
598         int     0x12
599 #if EBDA_EXTRA
600         sub     ax,#EBDA_EXTRA  ! allocate extra EBDA
601 #endif
602         shl     ax,#10-4        ; convert to paragraphs
603         mov     es,ax           ;
604         xor     di,di           ; DI = 0
605         shl     eax,#16         ; EAX is ES:DI
606         seg ss
607           xchg  eax,[4*0x13]    ; set new int 0x13 vector; get old
608         mov     [old13of],eax
609         mov     cx,#NEW13B/2    ; count of words to move
610         mov     si,#new13       ; source is DS:SI
611         rep
612           movsw                 ; move in the new drive mapper
613         seg es
614           mov   (di),cx         ; CX is zero from the move
615
616         pop     si
617         pop     cx
618         ret
619
620 ; Install drive mapper map
621 ;
622 ;       The map to use is at  ES:DI
623 ;       If there is an existing drive mapper, the two are merged.
624 ;       If there is no drive mapper, then one is installed.
625 ;
626 ;       Enter with  ES:DI  set to point at the map to install
627 ;               DS == CS
628 ;
629 ;       Exit with  DS=CX
630 ;               All registers are preserved
631 ;
632
633 install_map:
634         push    es
635         pusha           ; save all the regs
636         mov     bp,sp   ; save stack location
637
638 #ifdef DEBUG_NEW
639         call    im111
640         .asciz  "Install Map\r\n"
641 im111:  pop     si
642         call    say
643 #endif
644
645         seg es
646           cmp   word (di),#0
647         je      install_ret     ; nothing to do
648 COUNT   =  DRVMAP_SIZE*2
649         mov     cx,#COUNT       ; count of words
650         sub     sp,#COUNT*2     ; now allocate words
651         mov     si,di           ; ES:SI is now source
652         mov     di,sp           ; SS:DI is now destination
653
654         push    ds
655
656         push    es
657         pop     ds
658         push    ss
659         pop     es
660 install_move1:
661         lodsw                   ; get part of a map
662         stosw                   ; store it
663         or      ax,ax           ; test for null
664         jz      install_done1
665         loop    install_move1
666         jmp     fatal
667 install_done1:                  ; the map is at SS:SP
668         pop     ds
669
670 #ifdef DEBUG_NEW
671         mov     bx,sp           ; ES==SS
672         call    dump_drvmap
673 #endif
674
675         call    is_prev_mapper  ; is there a previous drive swapper
676                                 ; sets ES:DI
677         jnz     install_skip
678
679         call    swap13_null     ; install a new, null drive mapper
680                                 ; sets ES:DI to point at  drvmap  in swapper
681                                 ; which must be NULL terminated
682 install_skip:
683         mov     si,sp           ; SS:SI is place to do the map merge
684         push    ss
685         pop     ds              ; DS:SI is primary map
686         mov     bx,si           ; DS:BX receives the new map
687                                 ; and ES:DI points at the existing map
688         call    drive_map_merge
689
690 #ifdef DEBUG_NEW
691         mov     bx,sp
692         push    es
693
694         push    ss
695         pop     es
696         call    dump_drvmap
697
698         pop     es
699 #endif
700         mov     si,sp           ; DS:SI is the source
701         mov     cx,#COUNT
702         rep
703           movsw
704
705         push    cs
706         pop     ds              ; restore the DS
707
708 install_ret:
709         mov     sp,bp   ; get ready for pop
710         popa
711         pop     es
712         ret
713
714 fatal:  hlt
715         jmp     fatal
716
717 #ifdef DEBUG_NEW
718 wout:   push    ax
719         xchg    ah,al
720         call    bout            ! write hi-byte
721         pop     ax
722 bout:   push    ax              ! save byte
723         shr     al,#4           ! display upper nibble
724         call    nout
725         pop     ax
726 nout:   and     al,#0x0F        ! lower nible only
727         daa                     ! smaller conversion routine
728         add     al,#0xF0
729         adc     al,#0x40        ! AL is hex char [0..9A..F]
730 cout:
731         push    bx
732         mov     ah,#14          ! display, tty-style
733         mov     bx,#0007
734         int     0x10
735         pop     bx
736         ret
737
738 msg_new:
739         .ascii  "Found v.22 drive swapper"
740         .byte   13,10,0
741 msg_old:
742         .ascii  "Found v.21 drive swapper"
743         .byte   13,10,0
744 msg_swap13:
745         .ascii  "Drive Mapping"
746         .byte   13,10,0
747 msg_load:
748         .ascii  " - PT loaded"
749         .byte   13,10,0
750 msg_write:
751         .ascii  " - PT written"
752         .byte   13,10,0
753 no_update:
754         .ascii  "NO "
755 update:
756         .ascii  "24-25 update has occurred"
757 crlf:   .byte   13,10,0
758
759 #ifdef DEBUG_CONTINUE
760 msg_cont: .ascii  "\r\nHit any key to continue ..."
761         .byte   0
762 #endif
763
764 #endif  /* DEBUG_NEW */
765
766 #if 0
767 /* LILO version 21 (and maybe earlier) drive map header signature code */
768 new13_old:
769         push    ax              ! save AX (contains function code in AH)
770         push    bp              ! need BP to mess with stack
771         mov     bp,sp
772         pushf                   ! push flags (to act like interrupt)
773         push    si
774         mov     si,#drvmap-new13
775
776 new13_old_drvmap_offs   =       * - new13_old - 2
777 new13_old_length        =       new13_old_drvmap_offs
778 new13_old_min_offs      =       0x46    ; min seen in old code is 0x49
779 new13_old_max_offs      =       0x50    ; maxed out at  21.7.5 at 0x4d
780 #endif
781
782 #ifdef DEBUG_NEW
783 ; dump the drive map pointed to by  ES:BX
784 ;       Beware: DS != CS on some calls
785 ;
786 dump_drvmap:
787         pusha
788         push    ds
789
790         push    cs
791         pop     ds
792
793 sw13b:  seg es
794           mov   ax,(bx)         ; get drvmap entry
795         or      ax,ax
796         jz      sw13z
797         call    bout
798         mov     si,#sw13p
799         inc     bx
800         call    say
801         seg es
802           mov   al,(bx)
803         call    bout
804         inc     bx
805         mov     si,#crlf
806         call    say
807         jmp     sw13b
808 sw13z:
809         mov     si,#msg_swap13
810         call    say
811
812         pop     ds
813         popa
814         ret
815 sw13p:  .asciz  " -> "
816 #endif
817
818
819 #define CHAIN_LOADER
820 #include "mapper.S"
821
822 NEW13B  =   drvmap-new13
823
824 #if defined(LCF_REWRITE_TABLE)
825 prtmap: .blkw   PRTMAP_SIZE*2+1 ! only first word of last entry is read
826 #endif
827
828
829 #ifdef CHAIN
830         .org    *+4
831 #endif
832 theend:
833
834 #ifdef CHAIN
835 the_end1        = theend+511
836 theends =       the_end1/512
837         .org    theends*512-4
838         .long   CHAIN           ! boot signature check
839 #endif
840         .align  512
841 boot_sector: