9e91a244c72d02abe0f7542ad31b2996ea121ffb
[rrq/maintain_lilo.git] / src / second.S
1 #if 0
2 /* second.S  -  LILO second stage boot loader */
3 Copyright 1992-1998 Werner Almesberger.
4 Copyright 1999-2006 John Coffman.
5 All rights reserved.
6
7 Licensed under the terms contained in the file 'COPYING' in the 
8 source directory.
9
10 #endif
11
12 /*#define DEBUG*/
13 #define REG_DUMP 1
14 /*#define DELL_DIRTY_HACK*/
15 #define PIXADDRESS
16 #define MEMORY_CHECK
17 #define RETAIN
18 #define DNAME 1
19
20 #define LILO_ASM
21 #include "lilo.h"
22 get common.s            /* as86 "include" will bypass the CPP */
23
24 #define MAP Map
25 #define MAP2 Map2
26 #define DFLCMD Dflcmd
27 #define DESCR Descr
28 #define KEYTABLE Keytable
29 #define PARMLINE Parmline
30
31 #define DEBUG_INITRD 0
32
33 #ifdef DEBUG
34 #define DEBUG_NEW 1
35 #else
36 #if VERSION_MINOR<50
37 #define DEBUG_NEW 0
38 #else
39 #define DEBUG_NEW 1
40 #ifndef MEMORY_CHECK
41 #define MEMORY_CHECK
42 #endif
43 #endif          /* VERSION_MINOR */
44 #endif          /* DEBUG */
45
46 /* The following is set to 1 to enable map file writing */
47 #if DEBUG_NEW
48 # define WR_ENABLE 2
49 # if VERSION_MINOR>=90
50 #  undef WR_ENABLE
51 #  define WR_ENABLE 1
52 # endif
53 #else
54 # define WR_ENABLE 1
55 #endif
56
57
58 #if DEBUG_NEW==0 && !(WR_ENABLE&1)
59 #error "Retail version should have WR_ENABLE=1"
60 #endif
61
62 /* if compiling READONLY, then WR_ENABLE should never be used */
63 #ifdef LCF_READONLY
64 # undef WR_ENABLE
65 #endif
66
67 #if     ! NO_FS
68 #if DEBUG_NEW
69 #define CHECK_FS_VERBOSE 0
70 #define BEG_FS call fs_check
71 #else
72 #define BEG_FS
73 #endif
74 #define SEG_FS seg fs
75 #define END_FS
76 #else
77 #define BEG_FS db 0x1e,0x2e,0x8e,0x1e,0x02,0x00
78 /*      push ds; \
79         seg cs; \
80         mov     ds,firstseg */
81 #define SEG_FS
82 #define END_FS pop ds
83 #endif
84
85 /* get rid of the following to revert to old int 0x15/fn 0x88 mem scheme */
86 #define HIGHMEM_MAX 0x38000000
87
88 LOADSEG = SYSSEG                ; max kernel = 1024 sectors
89
90 #define UI_MAGIC 0xff           /* take input from keyboard */
91
92 #ifdef MENU
93 STAGE_MENU      =       STAGE_FLAG_MENU
94 X=MENU
95 #else
96 STAGE_MENU      =       0
97 #endif
98
99 #ifdef BITMAP
100 STAGE_BITMAP    =       STAGE_FLAG_BMP4
101 X=BITMAP
102 #else
103 STAGE_BITMAP    =       0
104 #endif
105
106 #ifdef LCF_NOSERIAL
107 STAGE_SERIAL    =       0
108 #else
109 STAGE_SERIAL    =       STAGE_FLAG_SERIAL
110 #endif
111
112 #ifdef TEXT
113 X=TEXT
114 #endif
115
116
117         .text
118
119         .globl  _main
120         .org    0
121
122 _main:  jmp     start
123
124 #if     NO_FS || DEBUG_NEW
125 firstseg:       dw      0
126 # if    DEBUG_NEW
127 #  define CHECK_FS call fs_check
128 # else
129 # define CHECK_FS
130 # endif
131 #endif
132 #ifndef CHECK_FS
133 # define CHECK_FS
134 #endif
135
136         .org    6
137
138 ! Boot device parameters. They are set by the installer.
139
140 sig:            .ascii  "LILO"
141 version:        .word   VERSION
142 mapstamp:       .long   0
143
144 stage:          .word   STAGE_SECOND|STAGE_SERIAL|STAGE_MENU|STAGE_BITMAP
145
146 port:   .byte   0               ; COM port (0 = unused, 1 = COM1, etc.)
147 sparam: .byte   0               ; serial port parameters (0 = unused)
148
149 timout: .word   0               ; input timeout
150 delay:  .word   0               ; boot delay
151 ms_len: .word   0               ; initial greeting message
152
153
154 kt_cx:  .word   0               ; keyboard translation table
155 kt_dx:  .word   0
156 kt_al:  .byte   0
157
158 flag2:  .byte   0               ; second stage specific flags
159
160
161 ! GDT for "high" loading
162
163         .align  16
164
165 gdt:    ; space for BIOS
166         .blkb   0x10
167         ; source
168         .word   0xffff          ; no limits
169         .byte   0
170         .word   LOADSEG>>4      ; start: 0x10000
171         .byte   0x93            ; permissions
172         .word   0               ; padding for 80286 mode :-(
173         ; destination
174         .word   0xffff          ; no limits
175         .word   0               ; start - filled in by user
176         .byte   0
177         .byte   0x93            ; permissions
178         .word   0               ; padding for 80286 mode :-(
179         ; space for BIOS
180         .blkb   0x10
181
182 start:  cld                     ; only CLD in the code; there is no STD
183 #if   ! NO_FS
184         push    ds
185         pop     fs              ; address parameters from here
186 #endif
187 #if     NO_FS || DEBUG_NEW
188         seg     cs
189         mov     firstseg,ds     ; save DS here
190 #endif
191
192         seg     cs
193         mov     [init_dx],dx    ; save DX passed in from first.S
194
195         int     0x12            ; get memory available
196         CHECK_FS
197 #if EBDA_EXTRA
198         sub     ax,#EBDA_EXTRA  ; allocate extra EBDA
199 #endif
200         shl     ax,#6           ; convert to paragraphs
201         sub     ax,#Dataend/16
202         mov     es,ax           ; destination address
203         push    cs
204         pop     ds
205         xor     si,si
206         xor     di,di
207         xor     ax,ax
208         mov     cx,#max_secondary/2     ; count of words to move
209         rep
210           movsw
211         add     di,#BSSstart-max_secondary
212         mov     cx,#BSSsize/2
213         rep
214           stosw
215         push    es
216         push    #continue
217         retf                    ; branch to continue address
218 continue:
219
220 #ifdef DELL_DIRTY_HACK
221 ;;;     push    dx              ; preserve DX (already saved)
222         mov     ax,#0x1200      ; enable video (VGA)
223         mov     bl,#0x36        ; (probably a nop on EGA or MDA)
224         int     0x10            ; video call
225         CHECK_FS
226 ;;;     pop     dx              ; restore DX on Dell geforce nVidia card
227 #endif
228
229
230 #ifndef LCF_NOSERIAL
231         call    serial_setup    ; set up the COM port, if any
232 #endif
233
234 #ifndef LCF_NODRAIN
235         mov     cx,#32          ; drain type-ahead buffer ?
236 drkbd:  mov     ah,#1           ; is a key pressed ?
237         int     0x16
238         jz      comcom          ; no -> done
239         xor     ah,ah           ; get the key
240         int     0x16
241         loop    drkbd
242 #endif
243
244 comcom:
245         CHECK_FS
246         mov     al,#0x4c        ; display an 'L'
247         call    display
248         push    #0              ; get pointer to disk parameter table in DS:SI
249         pop     ds
250         lds     si,[0x78]       ; 0x78 = 4*0x1E
251 #ifndef LCF_XL_SECS
252         cmp     byte ptr (si+4),#9 ; okay ?
253         ja      dskok           ; yes -> do not patch
254 #endif
255         push    cs              ; get pointer to new area in ES:DI
256         pop     es
257         mov     di,#dskprm
258         mov     cx,#6           ; copy 12 bytes
259         rep
260         movsw
261         seg     es              ; patch number of sectors
262 #ifndef LCF_XL_SECS
263         mov     byte ptr (di-8),#18
264 #else
265         mov     byte ptr (di-8),#LCF_XL_SECS
266 #endif
267         push    #0
268         pop     ds
269         cli                     ; paranoia
270         mov     [0x78],#dskprm
271         mov     [0x7a],es
272         sti
273 dskok:
274 #ifndef LCF_NOSERIAL
275         seg     cs              ; clear the break flag
276         mov     byte ptr break,#0
277 #endif
278         call    instto          ; get timer interrupt
279         CHECK_FS
280 ;;;     jmp     restrt          ; get going
281
282 ! Restart here after a boot error
283
284 restrt: mov     bx,cs           ; adjust segment registers
285         mov     ds,bx
286         mov     es,bx
287
288         sub     bx,#MAX_SETUPSECS*0x20+0x20     ; segment for setup code &
289                                                 ;   bootsect
290         mov     cx,#INITSEG
291         cmp     bx,cx
292         jbe     restrt1
293         mov     bx,cx           ; BX is the smaller segment #
294 restrt1:
295         mov     word ptr [map],#MAP
296         mov     [initseg],bx    ; set up INITSEG (was 0x9000)
297         lea     cx,(bx+0x20)
298         mov     [setupseg],cx   ; set up SETUPSEG (was 0x9020)
299         mov     cx,cs
300         sub     cx,bx           ; subtract [initseg]
301         shl     cx,#4           ; get stack size
302         mov     ss,bx           ; must lock with move to SP below
303         mov     sp,cx           ; data on the stack)
304 #if DEBUG_NEW
305         pusha
306
307         mov     bx,#msg_where
308         call    say
309         mov     ax,[initseg]
310         call    wout
311
312         mov     ax,[setupseg]
313         call    swout
314
315         mov     ax,cs
316         call    swout
317
318         mov     ax,ss
319         call    swout
320         mov     al,#0x3A        ; colon
321         call    display
322         mov     ax,sp
323         call    wout
324
325         mov     al,#32          ; space
326         call    display
327
328         BEG_FS
329         SEG_FS          ; external parameters ?
330         mov     ax,[EX_OFF+6]   ; DH:DL as passed to first.S
331         END_FS
332         call    swout
333
334         mov     ax,[init_dx]    ; DX into second Stage
335         call    swout
336
337 #ifdef LCF_NOKEYBOARD
338         call    nkbdbg0
339         .ascii " flags2="
340         .byte   0
341 nkbdbg0: pop    bx
342         call    say
343         mov     al,[par2_flag2]
344         call    bout
345 #endif
346
347         call    crlf
348
349 #if REG_DUMP
350         call    frd0
351  .ascii "Registers at startup of first stage loader:\n"
352  .ascii " AX   BX   CX   DX   SI   DI   BP   DS   ES\n"
353         .byte   0
354 frd0:   pop     bx
355         call    say
356
357         BEG_FS  
358         SEG_FS          ; external parameters ?
359         mov     ax,[EX_OFF-2-4] ; AX
360         call    wout
361         SEG_FS          ; external parameters ?
362         mov     ax,[EX_OFF-8-4] ; BX
363         call    swout
364         SEG_FS          ; external parameters ?
365         mov     ax,[EX_OFF-4-4] ; CX
366         call    swout
367         SEG_FS          ; external parameters ?
368         mov     ax,[EX_OFF-6-4] ; DX
369         call    swout
370         SEG_FS          ; external parameters ?
371         mov     ax,[EX_OFF-14-4]        ; SI
372         call    swout
373         SEG_FS          ; external parameters ?
374         mov     ax,[EX_OFF-16-4]        ; DI
375         call    swout
376         SEG_FS          ; external parameters ?
377         mov     ax,[EX_OFF-12-4]        ; BP
378         call    swout
379         SEG_FS          ; external parameters ?
380         mov     ax,[EX_OFF-18+16]       ; DS
381         call    swout
382         SEG_FS          ; external parameters ?
383         mov     ax,[EX_OFF-20+16]       ; ES
384         call    swout
385         END_FS
386
387         call    crlf
388 #endif
389
390         popa
391 #endif
392         cmp     dword [sig],#EX_MAG_HL  ; "LILO"
393         jne     crshbrn2
394         cmp     dword [mcmdbeg+6],#0x4547414d   ; "MAGE"  from BOOT_IMAGE
395         jne     crshbrn2
396         cmp     BYTE [stage],#STAGE_SECOND
397 #if 1
398         jne     crshbrn
399         cmp     WORD [version],#VERSION
400 #endif
401 crshbrn2: jne   crshbrn
402         mov     [cmdbeg],#acmdbeg       ; probably unattended boot
403
404         mov     di,#devmap      ; place to store the device map
405 #ifdef LCF_FIRST6
406         mov     ah,[init_dx]    ; AH is physical device
407         BEG_FS
408         SEG_FS
409         mov     al,[par1_secondary+0+SSDIFF]    ; map device logical
410         END_FS
411 #else
412         mov     ax,[init_dx]    ; AH is flags & device, AL is physical device
413         xchg    ah,al
414         and     ax,#DEV_MASK_asm<<8 | DEV_MASK_asm      ; mask to pure device codes
415 #endif
416         cmp     ah,al
417         je      end_tt
418 #if DEBUG_NEW
419         pusha
420         call    wout            ; TT entry, maybe
421         call    crlf
422         popa
423 #endif
424         stosw                   ; set up the translation from map -> boot
425 end_tt:
426         xor     ax,ax
427         stosw
428
429 ldsc:
430         BEG_FS
431         SEG_FS
432         mov     eax,[par1_mapstamp]
433         END_FS
434         cmp     eax,[par2_mapstamp]
435         jne     timeerr
436
437         call    kt_read         ; read the KEYTABLE
438
439         call    build_vol_tab
440
441         mov     bx,#DESCR
442         mov     si,#KEYTABLE+256+mt_descr
443 descr_more:
444         lodsw   
445         xchg    cx,ax
446         lodsw
447         xchg    dx,ax
448         lodsb
449         call    cread
450         jc      near fdnok      ; error -> retry
451         add     bh,#2           ; increment address
452         cmp     si,#KEYTABLE+256+mt_descr+sa_size*MAX_DESCR_SECS_asm
453         jb      descr_more
454
455         mov     si,#DESCR       ; compute a checksum of the descriptor table
456         mov     di,#SECTOR_SIZE*MAX_DESCR_SECS-4
457
458         push    dword #CRC_POLY1
459         call    crc32
460         add     di,si
461         cmp     eax,dword (di)
462         jz      nochkerr
463
464
465 ! Timestamp error
466 timeerr:
467         mov     bx,#msg_time
468         jmp     zz
469
470 ! Checksum error
471 chkerr:
472         mov     bx,#msg_chkerr
473         jmp     zz              ; go wait
474
475 crshbrn:
476         mov     bx,#msg_sigerr  ; signature not found
477 zz:     call    say
478 zzz:    hlt                     ; wait for interrupt
479         jmp     zzz             ; sit here forever
480
481
482 nochkerr:
483 #ifdef DEBUG
484         pusha
485         mov     bx,#nochker_msg
486         call    say
487         popa
488         jmp     nochkerr1
489 nochker_msg:
490         .ascii  "Descriptor checksum okay\n"
491         .byte   0
492 nochkerr1:
493 #endif
494 #ifdef LCF_VIRTUAL
495 ; remove those items that have "vmdisable", if virtual boot
496         call    vmtest
497         jnc     virtual_done
498         mov     di,#DESCR0      ; point at first descriptor
499 vir_loop:
500         test    byte ptr [id_name](di),#0xFF    ; test for NUL name
501         jz      virtual_done
502         test    word ptr [id_flags](di),#FLAG_VMDISABLE
503         jz      vir_skip
504
505         push    di
506         lea     si,[id_size](di)
507 vir_loop1:
508         mov     cx,#id_size
509         rep
510            movsb
511         test    byte ptr [id_name](di),#0xFF
512         jnz     vir_loop1
513
514         pop     di
515         jmp     vir_loop
516
517 vir_skip:
518         add     di,#id_size
519         jmp     vir_loop
520
521 virtual_done:
522 #endif
523 #ifdef LCF_NOKEYBOARD
524 ; remove those items that have "nokbdisable", if nokeyboard boot
525         call    kbtest
526         jc      kbd_done
527         mov     di,#DESCR0      ; point at first descriptor
528 kbd_loop:
529         test    byte ptr [id_name](di),#0xFF    ; test for NUL name
530         jz      kbd_done
531         test    word ptr [id_flags](di),#FLAG_NOKBDISABLE
532         jz      kbd_skip
533
534         push    di
535         lea     si,[id_size](di)
536 kbd_loop1:
537         mov     cx,#id_size
538         rep
539            movsb
540         test    byte ptr [id_name](di),#0xFF
541         jnz     kbd_loop1
542
543         pop     di
544         jmp     kbd_loop
545
546 kbd_skip:
547         add     di,#id_size
548         jmp     kbd_loop
549
550 kbd_done:
551 #endif
552
553 #if defined(MENU) || defined(BITMAP)
554         xor     bx,bx           ; defaults are all zero
555         mov     [dimage],bx     ; set default image to boot
556         mov     [abs_cx],bx     ; upper left of scroll area
557                                 ; means screen is not cleared
558 #endif
559
560         mov     bx,#KEYTABLE+256
561         mov     al,(bx+mt_flag)
562         BEG_FS
563         SEG_FS          ; get possible FLAG_NOBD
564         or      byte ptr [par1_prompt+SSDIFF],al
565         END_FS
566 #ifdef MENU
567         call    title_stuff
568 #endif
569         mov     bx,#DFLCMD
570 ;BEG_FS
571 ;SEG_FS
572         mov     cx,mt_dflcmd+KEYTABLE+256               ;DFCMD_OFF
573 ;SEG_FS
574         mov     dx,mt_dflcmd+2+KEYTABLE+256
575 ;SEG_FS
576         mov     al,mt_dflcmd+4+KEYTABLE+256
577 ;END_FS
578         call    cread
579         jc      fdnok           ; error -> retry
580         mov     bx,#DFLCMD
581         cmp     word ptr (bx),#DC_MAGIC ; okay ?
582         jne     bdcmag          ; no -> do not write
583 #ifndef LCF_READONLY
584         mov     word ptr (bx),#DC_MGOFF ; erase the magic number
585         call    cmd_write       ; write out the command line
586 #if 0
587 ; 22.6.2 -- removed, because this is worse that the first
588 ; command lock bug
589         mov     si,#DESCR0
590         lea     di,(bx+2)
591         mov     cx,#16
592         rep
593          movsb
594 ; 22.6.2
595 #endif
596
597 #endif
598         jmp     dokay           ; continue
599 bdcmag: mov     byte ptr (bx+2),#0 ; disable the command line
600         jmp     dokay           ; go on
601 fdnok:  
602 #if     0
603         xor     ax,ax           ; reset FDC
604         mov     dl,al
605         int     0x13
606 #endif
607         br      ldsc            ; retry
608
609 ! List all known boot images
610
611 list:   mov     byte ptr (bx),#0 ; set EOL marker
612         call    crlf
613 #ifdef MENU
614         inc     word [suppress] ; suppress console output
615 #endif
616         mov     si,#DESCR0      ; list all images
617         mov     cx,#IMAGES
618         xor     dl,dl           ; DL counts the images
619 lloop:  testb   (si),#0xff      ; done ?
620         jz      ldone           ; yes
621         mov     bx,si           ; display the name
622         call    say
623         add     si,#MAX_IMAGE_NAME+4
624         inc     dl              ; count the image
625         test    dl,#3           ; inside line -> go on
626         jnz     fill
627         call    crlf
628         jmp     imgdne          ; next image
629 fill:   push    bx              ; fill with spaces
630         mov     al,#0x20
631         call    display
632         pop     bx
633         inc     bx
634         cmp     bx,si
635         jbe     fill
636 imgdne: add     si,#id_size-MAX_IMAGE_NAME-4
637         loop    lloop           ; next image
638 ldone:  test    dl,#3           ; already at BOL ?
639         jz      atbol           ; yes -> no CRLF
640         call    crlf
641 atbol:  
642 #ifdef MENU
643         dec     word [suppress]
644 #endif
645         br      iloop           ; done
646
647 ! Ready to process user input
648
649 dokay:  mov     bx,#ospc        ; display 'O '
650         call    say
651 /* ifdef HIGHMEM_MAX */
652         xor     eax,eax
653         mov     dword ptr [hma],eax
654 /* #endif */
655         mov     ospc,al         ; disable the message
656         mov     word ptr vgaovr,#VGA_NOCOVR ; disable VGA override
657 ;;      BEG_FS
658 ;;      SEG_FS
659         xchg    ax,par2_delay           ;DSC_OFF-8+SSDIFF
660 ;;      END_FS
661         or      old_del,ax      ; remember delay
662         mov     nodfl,#iloop    ; interactive prompt if falling through
663 #ifdef LCF_NOKEYBOARD
664         call    kbtest          ; keyboard present?
665 #ifndef LCF_NOSERIAL
666         jc      kbd_present
667 ; no PC keyboard on the system, is there a serial port in use?
668         cmp     byte ptr [par2_port],#0
669         jz      skip_prompt     ; no serial keyboard either
670 #else
671         jnc     skip_prompt     ; skip check for prompt if no keyboard
672 #endif
673 kbd_present:
674 #endif
675         BEG_FS
676         SEG_FS          ; enter boot prompt ?
677         test    byte ptr par1_prompt+SSDIFF,#FLAG_PROMPT        ;DSC_OFF+15+SSDIFF,#0
678         END_FS
679         jnz     extp            ; yes -> check for external parameters
680 skip_prompt:
681         mov     nodfl,#bfirst   ; boot first image if falling through
682         call    waitsh          ; wait for a shifting key
683         jc      iloop           ; key pressed -> enter interactive mode
684
685 ! Check for external parameters
686
687 extp:   BEG_FS
688         SEG_FS          ; external parameters ?
689         cmp     byte ptr EX_OFF+6,#EX_DL_MAG
690         END_FS
691         jne     noex            ; no -> go on
692         BEG_FS
693         SEG_FS
694         mov     bl,EX_OFF+7     ; get drive
695         SEG_FS          ; clear flag
696         mov     byte ptr EX_OFF+6,bl    ; clear flag
697         SEG_FS          ; load the signature pointer
698         les     bx,EX_OFF
699         END_FS
700         seg     es
701         cmp     dword ptr (bx),#EX_MAG_HL       ; "LILO"
702         jne     noex            ; no -> go on
703         BEG_FS
704         SEG_FS
705         mov     si,EX_OFF+4     ; pointer to the command line
706         END_FS
707         seg     es
708         cmp     byte ptr (si),#0 ; empty ?
709         je      iloop           ; yes -> enter interactive mode
710         jmp     niloop          ; enter non-interactive mode
711
712 ! No external parameters after timeout -> boot first image
713
714 noex:   push    cs              ; restore ES
715         pop     es
716         mov     si,#DFLCMD+2    ; default command line ?
717         cmp     byte ptr (si),#0
718         jne     niloop          ; yes -> use it
719         mov     ax,nodfl        ; no idea how to tell as86 to do jmp (addr) :-(
720         jmp     ax              ; fall through
721
722
723 ; Command input processor
724
725 iloop:
726 #if defined(MENU) || defined(BITMAP)
727         call    menu_setup
728 #endif
729
730 #ifndef BITMAP
731 ;;      BEG_FS
732 ;;      SEG_FS          ; message disabled ?
733         cmp     word ptr par2_msg_len,#0                ;MSG_OFF+SSDIFF,#0
734 ;;      END_FS
735         je      nomsg           ; yes -> skip this
736         call    crlf
737 ;BEG_FS
738 ;SEG_FS         ; load the message file
739         mov     cx,mt_msg+KEYTABLE+256                  ;MSG_OFF+SSDIFF+2
740 ;SEG_FS
741         mov     dx,mt_msg+2+KEYTABLE+256
742 ;SEG_FS
743         mov     al,mt_msg+4+KEYTABLE+256
744 ;END_FS
745         mov     bx,[map]
746         call    sread
747         call    loadfile
748
749         xor     bx,bx           ; set the terminating NUL and disable further
750                                 ; messages
751         xchg    bx,par2_msg_len         ;MSG_OFF+SSDIFF
752
753         push    #SYSSEG
754         pop     ds
755         mov     byte ptr (bx),#0
756         xor     bx,bx           ; display the message
757         call    say
758
759         push    cs              ; restore segment registers
760         pop     ds
761 #endif
762
763 nomsg:  push    cs              ; disable external parameters
764         pop     es
765
766         mov     cmdbeg,#acmdbeg ; probably unattended boot
767         mov     si,#usrinpm     ; interactive mode
768 niloop:                         ; ES may point to external params
769         mov     bx,#msg_p       ; display boot prompt
770         call    say
771         mov     bx,#cmdline     ; move cursor to the end of the line
772 clend:  mov     al,(bx)
773         or      al,al           ; at end ?
774         jz      cledne          ; yes -> go on
775         push    bx              ; display the character
776         call    display
777         pop     bx
778         inc     bx              ; next one
779         jne     clend
780 cledne: mov     byte ptr prechr,#32 ; character before command line is a space
781
782 ! Input loop
783
784 input:  seg     es              ; interactive mode ?
785         cmp     byte ptr (si),#UI_MAGIC
786         je      kbinp           ; yes -> get keyboard input
787         seg     es              ; get non-interactive input
788         mov     al,(si)
789         inc     si
790         jmp     gotinp          ; go on
791         
792 tolist:
793 #ifdef BITMAP
794         call    menu_exit
795 #endif
796         br      list            ; ...
797
798 kbinp:  
799         mov     cx,#brto        ; get a key
800         call    getkey
801 #ifdef BITMAP
802         cmp     byte [abs_cx+1],#0
803         je      noNull          ; skip cursor keys after Tab
804 #endif
805 #if defined(MENU) || defined(BITMAP)
806         cmp     al,#0xE0        ; extended keyboard
807         je      toNull
808         or      al,al           ;
809 toNull: je      near null       ; cursor control
810 #endif
811 #ifndef MENU
812 noNull: or      al,al           ; keyboard NUL input?
813         je      input           ; yes, skip Keyboard NUL
814 ; stored command line NUL is handled differently
815 #endif
816 gotinp: cmp     al,#9           ; TAB ?
817         je      tolist          ; yes -> list images
818         cmp     al,#63          ; "?" ?
819         je      tolist          ; yes -> list images
820         or      al,al           ; NUL ?
821         je      nul             ; yes -> go on
822         cmp     al,#8           ; BS ?
823         je      todelch         ; yes -> erase one character
824         cmp     al,#13          ; CR ?
825         je      cr              ; yes -> go on
826         cmp     al,#127         ; DEL ?
827         je      todelch         ; yes -> erase one character
828         ja      input           ; non-printable -> ignore it
829         cmp     al,#21          ; ^U ?
830         je      todell          ; yes -> erase the line
831         cmp     al,#24          ; ^X ?
832         je      todell          ; yes -> erase the line
833         cmp     al,#32          ; ignore non-printable characters except space
834         jb      input
835         ja      noblnk          ; no space -> go on
836         cmp     (bx-1),al       ; second space in a row ?
837         je      input           ; yes -> ignore it
838 noblnk: cmp     bx,#cmdline+CL_LENGTH-1 ; at end of buffer ?
839         je      input           ; yes -> ignore
840         xor     ah,ah           ; cmdline is always NUL terminated
841         mov     (bx),ax         ; store in the buffer
842         inc     bx              ; increment pointer
843         push    bx
844         call    display         ; echo
845 #if defined(MENU) || defined(BITMAP)
846         push    ax
847         call    find_image      ; we want the side effect of the hilite
848         pop     ax
849 #endif
850         pop     bx
851         cmp     bx,#cmdline+1   ; first character ?
852         jne     input           ; no -> next input
853 #ifdef LCF_IGNORECASE
854         call    upcase          ; convert to upper case
855 #endif
856         mov     cx,#IMAGES      ; check if we have a single-key entry
857         mov     di,#DESCR0
858         mov     ah,al
859 sklp:   test    word ptr (di+id_flags),#FLAG_SINGLE ; single-key entry ?
860         jz      sknext          ; no -> try next
861         mov     al,(di)         ; get first character
862 #ifdef LCF_IGNORECASE
863         call    upcase          ; convert to upper case
864 #endif
865         cmp     al,ah           ; do we have a match ?
866         jne     sknext          ; no -> try next
867         cmp     byte ptr (di+1),#0 ; at end ?
868         je      cr              ; yes -> run it
869 sknext: add     di,#id_size     ; test next entry
870         loop    sklp            ; next one
871         br      input           ; done -> get more input
872
873 todelch:br      delch           ; ...
874 todell: br      delline         ; ...
875
876 ! End of input, process the command line
877
878 nul:    push    bx              ; automatic boot - wait for timeout
879         mov     ax,old_del
880         call    waitsh
881         pop     bx
882         jnc     crnul           ; no key pressed -> continue
883         mov     bx,#msg_int     ; interrupted -> display a message
884         call    say
885         mov     byte ptr cmdline,#0     ; clear the command line
886         br      iloop           ; return to interactive prompt
887
888 cr:
889 ;;22.7  mov     word par2_timeout,#0xffff       ; kill timeout
890 #ifdef LCF_HP_TTRC
891         push    ax              ; HP TTRC boot fail workaround.
892         mov     ax, #3          ; 2000/10 <yumoto@jpn.hp.com>
893         call    setto           ; reload timer
894 short_wait:
895         test    byte ptr timeout,#1 ; timed out ?
896         jz      short_wait      ; No, remain loop..
897         pop     ax
898 #endif
899         mov     cmdbeg,#mcmdbeg ; probably manual boot
900 crnul:
901 #ifndef LCF_NOSERIAL
902         mov     byte ptr break,#0 ; clear the break flag
903 #endif
904         push    cs              ; set ES to CS
905         pop     es
906         xor     al,al           ; mark end
907         mov     (bx),al
908         mov     si,#cmdline     ; copy command line to save buffer
909         mov     di,#lkcbuf
910         mov     byte ptr dolock,#0 ; disable locking
911
912 cpsav:  lodsb                   ; copy one byte
913         stosb
914         or      al,al           ; at end ?
915         jnz     cpsav           ; no -> go on
916
917         cmp     bx,#cmdline     ; empty line ?
918         je      notrspc         ; yes -> boot first image
919         cmp     byte ptr (bx-1),#32 ; trailing space ?
920         jne     notrspc         ; no -> go on
921         dec     bx              ; remove the space
922         mov     byte ptr (bx),al
923 notrspc:mov     si,#cmdline     ; scan the command line for "vga=", "kbd=",
924         mov     di,si           ; "lock" or "mem="
925 chkvga:
926
927 #ifdef LCF_BDATA
928 vsktnbd:
929         cmp     dword ptr (si),#0x64626f6e      ; "nobd"
930         jne     vsktv
931         cmp     byte (si+4),#32                 ; terminated with SP or NUL?
932         jnbe    vsktv
933         BEG_FS
934         SEG_FS          ; enter boot prompt ?
935         or      byte ptr par1_prompt+SSDIFF,#FLAG_NOBD  ; suppress BIOS data collection
936         END_FS
937         jmp     vskwd           ; skip word
938 #endif
939 vsktv:
940         cmp     dword ptr (si),#0x3d616776      ; "vga="
941         jne     vsktk
942         call    setvga          ; set VGA mode
943         jc      near iloop      ; error -> get next command
944         jmp     vskdb           ; proceed by discarding last blank
945 vsktk:
946         cmp     dword ptr (si),#0x3d64626b      ; "kbd="
947         jne     vsktl
948         call    putkbd          ; pre-load keyboard buffer
949         jmp     vskdb           ; proceed by discarding last blank
950 vsktl:
951         cmp     dword ptr (si),#0x6b636f6c      ; "lock"
952         jne     vsktm
953         cmp     byte (si+4),#32         ; space?
954         jnbe    vsktm
955         mov     byte ptr dolock,#1 ; enable locking
956 vskwd:  add     si,#4           ; skip word
957 vskdb:  dec     di              ; discard last blank
958         jmp     vsknb           ; continue
959 vsktm:
960 #if DEBUG_INITRD
961         cmp     dword ptr (si),#0x3d647269      ; "ird="
962 #else
963         cmp     dword ptr (si),#0x3d6d656d      ; "mem="
964 #endif
965         jne     vsknb
966         call    getmem          ; get the user-provided memory limit
967 vsknb:
968         lodsb                   ; copy one byte
969         stosb
970         cmp     al,#32          ; space ?
971         je      chkvga          ; yes -> look for options again
972         or      al,al           ; at end ?
973         jnz     vsknb           ; no -> go on
974         call    crlf            ; write CR/LF
975         cmp     di,#cmdline+1   ; empty line ?
976 emptyl: je      bfirst          ; yes -> boot first image
977         jmp     bcmd            ; boot the specified image
978
979 ! Find the boot image and start it
980
981 bcmd:
982         call    find_image
983         jc      near boot       ; eureka, it was found
984
985         mov     bx,#msg_nf      ; not found -> display a message
986         call    say
987         br      iloop           ; get more input
988
989 ! Delete one character
990
991 delch:  cmp     bx,#cmdline     ; at the beginning ?
992         je      toinput         ; yes -> do nothing
993         dec     bx              ; move the pointer
994         push    bx              ; display[B BS,SPC,BS
995         mov     bx,#bs
996         call    say
997 #if defined(MENU) || defined(BITMAP)
998         pop     bx
999         push    bx
1000         mov     byte (bx),#0    ; NUL terminate the line
1001         mov     ax,#cmdline
1002         sub     ax,bx
1003         jz      delch6
1004         call    find_image
1005         jmp     delch9
1006
1007 delch6:
1008 #if defined(LCF_VIRTUAL) || defined(LCF_NOKEYBOARD)
1009         mov     ax,[vimage]
1010 #endif
1011         mov     bx,[dimage]
1012         cmp     ax,bx
1013         je      delch9
1014         xchg    ax,bx
1015         call    lowlite
1016         xchg    ax,bx
1017         call    hilite
1018 delch9:
1019 #endif
1020         pop     bx
1021 toinput:br      input           ; go on
1022
1023 ! Delete the entire line
1024
1025 delline:
1026 #if !defined(MENU) && !defined(BITMAP)
1027         cmp     bx,#cmdline     ; done ?
1028         je      toinput         ; yes -> go on
1029         push    bx              ; display BS,SPC,BS
1030         mov     bx,#bs
1031         call    say
1032         pop     bx
1033         dec     bx              ; move the pointer
1034         jmp     delline         ; next one
1035 #else
1036         call    menu_delline
1037         push    bx              ; delch will do a pop
1038         xor     ax,ax
1039         jmp     delch6
1040 #endif
1041
1042 ! Boot first after timeout
1043
1044 brto:   call    crlf            ; display a CRLF
1045         jmp     brfrst          ; boot
1046
1047 ! Boot the first image
1048
1049 bfirst: mov     byte ptr lkcbuf,#0  ; clear default
1050         cmp     byte ptr cmdline,#0 ; is there a default ?
1051         jne     bcmd            ; yes -> boot that image
1052 brfrst: 
1053         mov     bx,#DESCR0      ; boot the first image
1054
1055 #if defined(LCF_VIRTUAL) && defined(LCF_NOKEYBOARD)
1056         xor     ax,ax           ; mask = 0
1057         call    vmtest
1058         jnc     brfrst0v        ; not virtual
1059         mov     ax,#FLAG_VMDEFAULT
1060 brfrst0v:
1061         call    kbtest
1062         jc      brfrst0k
1063         mov     ax,#FLAG_NOKBDEFAULT
1064 brfrst0k:
1065
1066         mov     cx,#IMAGES
1067 brfrst1: test   word ptr (bx+id_flags),ax
1068         jnz     brfrst3
1069         add     bx,#id_size
1070         loop    brfrst1 
1071
1072         mov     bx,#DESCR0      ; restore default
1073 brfrst3:
1074 #else
1075 #ifdef LCF_VIRTUAL
1076         call    vmtest
1077         jnc     brfrst3         ; not virtual, boot BX
1078
1079         mov     cx,#IMAGES
1080 brfrst1: test   word ptr (bx+id_flags),#FLAG_VMDEFAULT
1081         jnz     brfrst3
1082         add     bx,#id_size
1083         loop    brfrst1 
1084
1085         mov     bx,#DESCR0      ; restore default
1086 brfrst3:
1087 #endif  /* LCF_VIRTUAL */
1088 #ifdef LCF_NOKEYBOARD
1089         call    kbtest
1090         jc      brfrst3k                ; not virtual, boot BX
1091
1092         mov     cx,#IMAGES
1093 brfrst1k: test  word ptr (bx+id_flags),#FLAG_NOKBDEFAULT
1094         jnz     brfrst3k
1095         add     bx,#id_size
1096         loop    brfrst1k
1097
1098         mov     bx,#DESCR0      ; restore default
1099 brfrst3k:
1100 #endif  /* LCF_NOKEYBOARD */
1101
1102 #endif /* if !both */
1103
1104         mov     si,bx           ; copy the name to the command line
1105         mov     di,#cmdline
1106 bfcpl:  lodsb                   ; copy one character
1107         mov     (di),al
1108         inc     di
1109         or      al,al           ; NUL ?
1110         jnz     bfcpl           ; no -> next one
1111
1112 ! Boot the image BX points to (with password check)
1113
1114 boot:
1115         mov     word par2_timeout,#0xffff       ; kill timeout  (22.7)
1116         mov     si,#cmdline     ; locate start of options
1117 locopt: lodsb
1118         or      al,al           ; NUL ?
1119         je      optfnd          ; yes -> no options
1120         cmp     al,#32          ; space ?
1121         jne     locopt          ; no -> continue searching
1122         cmp     byte ptr (si),#0 ; followed by NUL ?
1123         jne     optfnd          ; no -> go on
1124         mov     byte ptr (si-1),#0 ; discard trailing space
1125 optfnd: dec     si              ; adjust pointer
1126         mov     options,si      ; store pointer for later use
1127 #ifdef BITMAP
1128 #ifdef RETAIN
1129         test    word ptr [id_flags](bx),#FLAG_RETAIN    ; keep bitmap?
1130         jz      bmp_terminate
1131         xor     ax,ax           ; time out immediately
1132         call    waitsh          ; check for break (Shift, Alt, ScrollLock,...)
1133         jnc     bmp_retain
1134 bmp_terminate:
1135 #endif
1136         call    menu_exit
1137 bmp_retain:
1138 #endif
1139
1140 #ifdef LCF_VIRTUAL
1141         test    word ptr [id_flags](bx),#FLAG_VMWARN
1142         jz      boot9
1143         call    vmtest          ; 'vmwarn' there, is it actually virt. boot
1144         jnc     boot9
1145 ; VMWARN set, and is virtual boot, so issue comment
1146 ;;      BEG_FS
1147 ;;      SEG_FS
1148         mov     word ptr par2_timeout,#0xffff   ; cancel timeout
1149 ;;      END_FS
1150
1151         push    bx              ; save image descriptor ptr
1152         mov     bx,#msg_vmwarn
1153         call    say
1154         mov     cx,#vmwto       ; timeout exit
1155         call    getkey
1156
1157         push    ax
1158         cmp     al,#0x20        ; compare to Space
1159         jb      boot3           ; no echo if ctrl char
1160         call    display         ; echo
1161 boot3:  call    crlf
1162         pop     ax
1163
1164         pop     bx              ; restore image descriptor ptr
1165         cmp     al,#0x79        ; y is yes
1166         je      boot9
1167         cmp     al,#0x59        ; Y is yes
1168         je      boot9
1169
1170 vmwto:
1171         br      iloop
1172
1173 boot9:
1174 #endif
1175         test    byte ptr (bx+id_flags),#FLAG_PASSWORD   ; use a password
1176         jz      toboot          ; no -> boot
1177         test    byte ptr (bx+id_flags),#FLAG_RESTR      ; restricted ?
1178         jz      dopw            ; no -> get the password
1179         cmp     byte ptr (si),#0 ; are there any options ?
1180         jne     dopw            ; yes -> password required
1181 toboot: br      doboot          ; ...
1182 dopw:
1183 #if defined(CRC_PASSWORDS) || defined(SHS_PASSWORDS)
1184         push    bx              ; save the image descriptor
1185 ;;      BEG_FS
1186 ;;      SEG_FS
1187         mov     word ptr par2_timeout,#0xffff   ; cancel timeout
1188 ;;      END_FS
1189         mov     bx,#msg_pw      ; display a prompt
1190         call    say
1191
1192         push    bp              ; save BP
1193         mov     bp,sp           ; save SP in BP
1194         sub     sp,#CL_LENGTH   ; allocate space for PW string
1195         mov     si,sp           ; si points at string
1196         xor     di,di           ; di counts characters
1197 pwloop:
1198 #ifdef DEBUG
1199         pusha
1200         mov     ax,si
1201         call    wout
1202         mov     al,#32
1203         call    display
1204         mov     ax,di
1205         call    wout
1206         call    crlf
1207         popa
1208 #endif
1209         mov     cx,#pwtime      ; get timeout exit
1210         call    getkey
1211         
1212         cmp     al,#13          ; CR ?
1213         je      pwcr            ; yes -> handle it
1214         cmp     al,#21          ; ^U ?
1215         je      pwdell          ; yes -> erase line
1216         cmp     al,#24          ; ^X
1217         je      pwdell
1218         cmp     al,#8           ; BS ?
1219         je      pwdelch         ; yes -> erase one character
1220         cmp     al,#127         ; DEL
1221         je      pwdelch
1222         ja      pwloop          ; ignore other non-printable characters
1223         cmp     al,#32
1224         jb      pwloop
1225
1226         cmp     di,#CL_LENGTH   ; check for buffer overflow
1227         jae     pwloop          ; ingnore further input
1228         seg     ss
1229         mov     (si),al         ; store char in buffer
1230         inc     si
1231         inc     di
1232         mov     al,#42          ; echo '*'
1233         call    display
1234         jmp     pwloop          ; loop back for more
1235
1236 pwdelch: or     di,di
1237         jz      pwloop 
1238         call    pwbs
1239         dec     si
1240         dec     di
1241         jmp     pwloop
1242
1243 pwdell: inc     di
1244 pwdel:  dec     di
1245         jz      pwloop
1246         call    pwbs
1247         dec     si
1248         jmp     pwdel
1249
1250 pwbs:   mov     bx,#bs
1251         call    say
1252         ret
1253
1254 pwcr:   
1255         xor     cx,cx           ; signal okay
1256 pwtime:                         ; CX != 0 if enter here
1257         inc     cx
1258         call    crlf
1259
1260         sub     si,di           ; point SI at start of buffer
1261         push    es              ; save ES
1262
1263 #if !defined(SHS_PASSWORDS)
1264         mov     bx,(bp+2)       ; restore image descriptor pointer
1265         push    ss
1266         pop     es              ; ES:SI points at char string
1267
1268 #if MAX_PW_CRC>=1
1269         push    dword #CRC_POLY1
1270         call    crc32
1271 #ifdef DEBUG
1272         pusha
1273         push    ax
1274         mov     ax,di
1275         call    wout
1276         mov     al,#32
1277         call    display
1278         pop     ax
1279
1280         push    eax
1281         call    dout
1282         call    crlf
1283         popa
1284 #endif
1285
1286         cmp     eax,(bx+id_password_crc)
1287         jne     pwcleanup
1288 #endif
1289
1290 ; insert other checks in here
1291 #if MAX_PW_CRC>=2
1292         push    dword #CRC_POLY2
1293         call    crc32
1294         cmp     eax,(bx+id_password_crc+4)
1295         jne     pwcleanup
1296 #endif
1297
1298 #if MAX_PW_CRC>=3
1299         push    dword #CRC_POLY3
1300         call    crc32
1301         cmp     eax,(bx+id_password_crc+8)
1302         jne     pwcleanup
1303 #endif
1304
1305 #if MAX_PW_CRC>=4
1306         push    dword #CRC_POLY4
1307         call    crc32
1308         cmp     eax,(bx+id_password_crc+12)
1309         jne     pwcleanup
1310 #endif
1311
1312 #if MAX_PW_CRC>=5
1313         push    dword #CRC_POLY5
1314         call    crc32
1315         cmp     eax,(bx+id_password_crc+16)
1316         jne     pwcleanup
1317 #endif
1318 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1319         dec     cx                      ; signal all okay
1320 #else           /* SHS_PASSWORDS */
1321 ; DI is the count
1322 ; SS:SI is the password string
1323         push    di
1324         push    si
1325         call    _shsInit
1326         call    _shsUpdate
1327         call    _shsFinal
1328         mov     bx,(bp+2)       ; restore image descriptor pointer
1329         lea     di,(bx+id_password_crc)
1330         mov     si,#shs_digest
1331         mov     cx,#MAX_PW_CRC*4
1332 ; ES==DS
1333         repe
1334             cmpsb
1335
1336         pop     si              ; restore buffer ptr
1337         pop     di              ; clear stack
1338         push    ss
1339         pop     es              ; ES=SS
1340
1341         je      pwcleanup       ; CX will be 0
1342         inc     cx              ; CX is > 0
1343 #endif          /* !defined(SHS_PASSWORDS) */
1344
1345 pwcleanup:
1346         push    cx
1347         mov     cx,#CL_LENGTH
1348         mov     di,si
1349         xor     ax,ax
1350         rep                     ; wipe out password in memory
1351             stosb
1352         pop     cx
1353         pop     es              ; restore the saved ES
1354
1355         mov     sp,bp
1356         pop     bp
1357         pop     bx
1358         or      cx,cx           ; test CX==0 means all okay
1359         jz      doboot
1360 ; fall into pwfail      
1361
1362 #else
1363         push    bx              ; save the image descriptor
1364         lea     si,(bx+MAX_IMAGE_NAME+1) ; get a pointer to the password string
1365         mov     bx,#msg_pw      ; display a prompt
1366         call    say
1367 pwagain:xor     cl,cl           ; CL counts characters after a mismatch
1368 pwloop: push    cx              ; get a key
1369         mov     cx,#pwtime
1370         call    getkey
1371         pop     cx
1372         cmp     al,#13          ; CR ?
1373         je      pwcr            ; yes -> handle it
1374         cmp     al,#21          ; ^U ?
1375         je      pwdell          ; yes -> erase line
1376         cmp     al,#24          ; ^X
1377         je      pwdell
1378         cmp     al,#8           ; BS ?
1379         je      pwdelch         ; yes -> erase one character
1380         cmp     al,#127         ; DEL
1381         je      pwdelch
1382         ja      pwloop          ; ignore other non-printable characters
1383         cmp     al,#32
1384         jb      pwloop
1385         or      cl,cl           ; counting bad input ?
1386         jnz     pwbad           ; yes -> do it
1387         cmp     al,(si)         ; correct input ?
1388         je      pwgood          ; yes -> go on
1389 pwbad:  inc     cl              ; count error
1390         jnz     pwgood          ; no overflow -> go on
1391         dec     cl              ; adjust it
1392         jmp     pwcr            ; terminate input
1393 pwgood: inc     si              ; good character -> go on
1394         jmp     pwloop
1395 pwdell: pop     si              ; reset the pointer
1396         push    si
1397         add     si,#MAX_IMAGE_NAME+1
1398         jmp     pwagain         ; get password again
1399 pwdelch:pop     bx              ; at the beginning of the line ?
1400         push    bx
1401         add     bx,#MAX_IMAGE_NAME+1
1402         cmp     si,bx
1403         je      pwloop          ; yes -> ignore it
1404         dec     si              ; remove one character
1405         sub     cl,#1
1406         jnc     pwloop          ; no underflow -> go on
1407         inc     cl              ; adjust it
1408         jmp     pwloop          ; next character
1409 pwtime: pop     cx              ; drop CX ...
1410         mov     cl,#1           ; ... and fail
1411 pwcr:   call    crlf
1412         pop     bx              ; restore the image descriptor
1413         or      cl,cl           ; no errors ?
1414         jnz     pwfail          ; no -> fail
1415         cmp     byte ptr (si),#0 ; at end ?
1416         je      doboot          ; yes -> continue booting
1417 #endif  /* CRC_PASSWORDS */
1418
1419 pwfail: mov     bx,#msg_pf      ; display an error message
1420         call    say
1421         br      iloop           ; get next input
1422
1423 ! Boot the image BX points to
1424
1425 doboot: mov     byte ptr prechr,#61 ; switch to equal sign
1426         push    bx              ; save image descr
1427         mov     bx,#msg_l       ; say hi
1428         call    say
1429         pop     bx              ; display the image name
1430         push    bx
1431         call    say
1432         pop     si
1433
1434         push    si
1435         add     si,#id_start    ; form address
1436         
1437 ;  Now load the kernel sectors
1438         xor     ax,ax
1439         mov     word ptr (gdt+0x1b),ax ; set GDT to "load low"
1440         mov     byte ptr (gdt+0x1f),al
1441         mov     moff,ax         ; map is not loaded yet
1442
1443         lodsw                   ; address of the first map sector
1444         xchg    cx,ax
1445         lodsw
1446         xchg    dx,ax
1447         lodsb
1448
1449         push    si              ; save SI
1450
1451 #ifdef DEBUG
1452         push    ax              ;
1453         mov bx,#step0
1454         call say
1455         pop     ax              ;
1456 #endif
1457         mov     bx,[map]                ; load the first map sector
1458         call    sread
1459 #ifdef DEBUG
1460         mov bx,#step0b
1461         call say
1462 #endif
1463         mov     bx,#DFLCMD      ; load the default command line
1464 ;BEG_FS
1465 ;SEG_FS
1466         mov     cx,mt_dflcmd+KEYTABLE+256
1467 ;SEG_FS
1468         mov     dx,mt_dflcmd+2+KEYTABLE+256
1469 ;SEG_FS
1470         mov     al,mt_dflcmd+4+KEYTABLE+256
1471 ;END_FS
1472         call    cread
1473         push    word ptr (DFLCMD) ; push magic number
1474         mov     bx,#DFLCMD      ; load the fallback sector
1475         call    load1
1476         pop     ax              ; valid magic number ?
1477 #ifndef LCF_READONLY
1478         cmp     ax,#DC_MAGIC
1479         je      dclok           ; yes -> can write
1480         cmp     ax,#DC_MGOFF
1481         jne     nofbck          ; invalid -> must not write
1482 dclok:  mov     bx,#DFLCMD      ; fallback data present ?
1483         cmp     word ptr (bx),#DC_MAGIC
1484         jne     nofbck          ; no -> go on
1485         call    cmd_write       ; write out the command line
1486 nofbck:
1487 #endif
1488 #ifdef DEBUG
1489         mov bx,#step1
1490         call say
1491 #endif
1492         mov     bx,#DFLCMD      ; load the options sector
1493         call    load1
1494         mov     si,cmdbeg       ; copy non-options part of command line
1495         mov     di,#PARMLINE
1496         mov     cx,#CL_LENGTH-1 ; max number of characters to copy
1497
1498 cpnocl: 
1499 #if DNAME
1500         cmp     si,#cmdline
1501 #else
1502         cmp     si,options      ; at beginning of options ?
1503 #endif
1504         je      cpnodn          ; yes -> go on
1505         movsb                   ; copy one byte
1506         loop    cpnocl          ; next one
1507         jmp     cpovfl          ; signal overflow
1508
1509 cpnodn: 
1510 #if DNAME
1511         pop     ax              ; get saved pointer
1512         pop     si              ; get saved descriptor
1513         push    si
1514         push    ax
1515 cpdname:
1516         lodsb
1517         or      al,al
1518         jz      cpdname9
1519         stosb
1520         dec     cx
1521         jmp     cpdname
1522 cpdname9:       
1523 #endif
1524         mov     si,#DFLCMD      ; constant options ?
1525         cmp     byte ptr (si),#0
1526         je      nocopt          ; no -> go on
1527         mov     al,#32          ; add a space
1528         stosb
1529         dec     cx              ; count character
1530         jz      cpovfl
1531 cpcodsp:
1532 #if DEBUG_INITRD
1533         cmp     dword ptr (si),#0x3d647269      ; "ird="
1534 #else
1535         cmp     dword ptr (si),#0x3d6d656d      ; "mem="
1536 #endif
1537         jne     cpnotmem
1538         call    getmem          ; get the user-provided memory limit
1539 cpnotmem:
1540         lodsb                   ; fetch next byte
1541         cmp     al,#32          ; space ?
1542         je      cpcodsp         ; yes -> discard it
1543 cpcolp: or      al,al           ; NUL ?
1544         jz      cpcodn          ; yes -> done
1545         stosb                   ; store byte
1546         dec     cx              ; count character
1547         jz      cpovfl
1548         cmp     al,#32          ; a space ?
1549         je      cpcodsp         ; yes -> discard next
1550         lodsb                   ; get next byte
1551         jmp     cpcolp
1552
1553 cpcodn: seg     es
1554         cmp     byte ptr (di-1),#32 ; last was space ?
1555         jne     nocopt          ; no -> go on
1556         dec     di              ; discard it
1557         inc     cx              ; **
1558 nocopt: mov     si,options      ; append variable options
1559 cpvalp: lodsb                   ; copy one byte
1560         stosb
1561         or      al,al           ; NUL ?
1562         jz      cpdone          ; done?
1563         loop    cpvalp          ; count and loop back
1564 cpovfl: mov     (di),cl         ; CX is zero
1565 #if DEBUG_NEW
1566         dec     cx              ; count 1 more character
1567 #endif
1568 cpdone:
1569
1570
1571 #if DEBUG_NEW
1572         push    cx
1573         mov     bx,#msg_pl      ; parameter line message
1574         call    say
1575         pop     cx
1576         mov     ax,#CL_LENGTH-1
1577         sub     ax,cx
1578         call    wout
1579         call    crlf
1580 #endif
1581
1582 #ifdef DEBUG
1583         mov bx,#step2
1584         call say
1585 #endif
1586         mov     es,[initseg]    ; load the original boot sector
1587         xor     bx,bx           ; load now
1588         call    load1
1589         pop     si              ; restore SI
1590         lodsw                   ; get flags bit map
1591         xchg    bx,ax           ; move to BX
1592         lodsw                   ; copy parameters ... VGA mode ... (done)
1593         cmp     word ptr vgaovr,#VGA_NOCOVR ; VGA mode not overridden on
1594                                 ; command line ?
1595         je      vganorm         ; no -> go on
1596         mov     ax,vgaovr       ; use that value
1597         jmp     vgaset
1598 vganorm:test    bx,#FLAG_VGA
1599         jz      novga
1600 vgaset: seg     es
1601          mov    [VGA_SET],ax    ; magic offset in the boot sector
1602 novga:  push    bx              ; use flags (BX) later
1603         test    bx,#FLAG_LOCK   ; ... lock target ?
1604         jnz     lockit          ; yup -> do it
1605         cmp     byte ptr dolock,#0 ; did user ask to lock new target ?
1606         je      nolock          ; no -> go on
1607 lockit:
1608 #ifndef LCF_READONLY
1609         mov     bx,#lkwbuf      ; save the command line
1610         mov     word (bx),#DC_MAGIC     ;
1611         push    es
1612         push    si
1613
1614         push    ds                      ;
1615         pop     es                      ;
1616         call    cmd_write               ; write out the command line
1617
1618         pop     si
1619         pop     es
1620 #endif
1621 nolock:
1622 #ifdef DEBUG
1623         mov bx,#step3
1624         call say
1625 #endif
1626         xor     cx,cx
1627         seg     es
1628           add   cl,[VSS_NUM]
1629 ;;;     or      cx,cx
1630         jnz     lsetup
1631         mov     cl,#SETUPSECS   ; default is to load four sectors
1632 lsetup: 
1633         mov     es,[setupseg]   ; load the setup codes
1634
1635 #ifdef MEMORY_CHECK
1636         mov     ax,cx           ; number of sectors to AX
1637         shl     ax,#5           ; convert to paragraphs (9-4)
1638         mov     bx,es
1639         add     bx,ax
1640         add     bx,#STACK>>4    ; allow for stack space in paragraphs
1641         mov     ax,cs           ;
1642         cmp     bx,ax
1643         jbe     enough_mem
1644         mov     bx,#msg_mem     ; we are very short on memory
1645         call    say
1646
1647 enough_mem:
1648 #endif
1649
1650         xor     bx,bx           ; other operating system)
1651 lsloop: push    cx
1652         call    loadopt
1653         pop     cx
1654         loop    lsloop
1655 #ifdef DEBUG
1656         mov bx,#step4
1657         call say
1658 #endif
1659         pop     bx              ; get flags
1660         test    bx,#FLAG_MODKRN ; "modern" kernel ?
1661         jz      loadlow         ; no -> avoid all patching and such
1662         seg     es              ; set loader version
1663         mov     byte ptr (16),#LOADER_VERSION
1664
1665         test    bx,#FLAG_LOADHI ; load kernel high
1666         jz      nohigh
1667         
1668         seg     es
1669         mov     ax,word ptr (20+1) ; get start address  00 1000 00
1670         mov     (gdt+0x1b),ax
1671         seg     es
1672         mov     al,byte ptr (20+3) ; get hi-byte of address
1673         mov     (gdt+0x1f),al
1674 nohigh:
1675
1676         seg     es              ; version >= 1 ?
1677         cmp     word ptr (6),#NEW_HDR_VERSION
1678         jbe     noheap          ; no -> do not patch heap
1679         mov     ax,cs
1680         sub     ax,[initseg]    ; find no. of paragraphs available
1681         shl     ax,4
1682         add     ax,#SLA_SIZE_DYN
1683         seg     es
1684         mov     word ptr (36),ax
1685         seg     es              ; patch flags
1686         or      byte ptr (17),#LFLAG_USE_HEAP
1687 noheap:
1688         pop     si              ; restore pointer to DESCR to load
1689
1690         push    [gdt+0x1b]
1691         mov     al,[gdt+0x1f]
1692         push    ax
1693
1694         call    load_initrd     ; load the initrd & patch header
1695
1696         pop     ax
1697         mov     [gdt+0x1f],al
1698         pop     bx
1699         mov     [gdt+0x1b],bx
1700
1701         cbw
1702         or      ax,bx           ; load low ?
1703
1704         je      loadlow         ; yes -> do it
1705         xor     ax,ax           ; GDT is already set up ...
1706         mov     es,ax
1707         mov     bx,#gdt
1708 #if DEBUG_NEW
1709         push    bx
1710         mov     bx,#msg_high
1711         call    say
1712         pop     bx
1713 #endif
1714         call    lfile           ; load the system ...
1715         jmp     launch2         ; ... and run it
1716 loadlow:
1717 #if DEBUG_NEW
1718         push    bx
1719         mov     bx,#msg_low
1720         call    say
1721         pop     bx
1722 #endif
1723         call    loadfile        ; load the system
1724 launch2:
1725
1726         jmp     launch          ; go !
1727
1728 loadfile:
1729         push    #SYSSEG         ; load a file at SYSSEG:0000
1730         pop     es
1731         xor     bx,bx
1732 lfile:  call    load
1733         jmp     lfile
1734
1735 ! Load one sector. Issue an error at EOF.
1736
1737 load1:  call    loadit          ; load the sector
1738         mov     bx,#msg_eof     ; we only get here at EOF
1739         call    say
1740         br      restrt
1741
1742 loadit: call    load            ; load it
1743         pop     ax              ; drop return address of load1
1744         ret
1745
1746 ! Load one sector. Start the system at EOF.
1747
1748 loadopt:call    loadit          ; load the sector
1749         jmp     launch          ; go
1750
1751 ! Load one sequence of sectors. Leave outer function at EOF.
1752
1753 load:   push    es              ; save ES:BX
1754         push    bx
1755 lfetch: mov     si,moff         ; get map offset
1756         mov     bx,[map]
1757         mov     cx,(bx+si)      ; get address
1758         mov     dx,(bx+si+2)
1759         mov     al,(bx+si+4)
1760         or      cx,cx           ; at EOF ?
1761         jnz     noteof          ; no -> go on
1762         or      dx,dx
1763         jnz     noteof
1764         pop     bx              ; restore ES:BX
1765         pop     es
1766         pop     ax              ; pop return address
1767         ret                     ; return to outer function
1768 noteof: add     si,#sa_size     ; increment pointer
1769         mov     moff,si
1770         cmp     si,#SECTOR_SIZE - sa_size + 1           ; page end ?
1771         jb      near doload
1772
1773         mov     moff,#0         ; reset pointer
1774         push    cs              ; adjust ES
1775         pop     es
1776
1777         mov     bl,hinib        ; this might get clobbered
1778         push    bx              ; so save it
1779         mov     bx,[map]                ; load map page
1780         call    sread
1781         pop     ax              ; restore the hi-nibble
1782         mov     hinib,al        ; 
1783
1784         mov     al,#0x2e        ; print a dot
1785         call    display
1786         jmp     lfetch          ; try again
1787
1788 ! Start the kernel
1789
1790 launch:
1791 ; terminate emulation if CD boot
1792         test    byte ptr [par2_flag2],#FLAG2_EL_TORITO  ; a CD?
1793         jz      not_el_torito
1794         mov     si,#Map         ; empty command packet
1795         mov     byte ptr (si),#0x13     ; size of command packet
1796         mov     ax,#0x4b00      ; terminate emulation
1797 ;;;;    mov     dl,al           ; DL is 0
1798         mov     dl,[init_dx]    ; terminate boot device
1799         int     0x13
1800 not_el_torito:
1801 #ifdef MENU
1802         call    menu_exit       ; make the menu area vanish
1803 #endif
1804         call    crlf            ; display a CRLF
1805
1806 /* 'outb' was removed in 22.5.5; but the HW stop is required by some BIOSs */
1807         mov     dx,#0x3f2       ; stop the floppy motor
1808         xor     ax,ax
1809         out     dx,al           ; outb
1810         mov     dl,al
1811         int     0x13            ; reset the FDC  (AH=0)
1812
1813         mov     es,[initseg]    ; adjust segment registers
1814         mov     di,#PARMLINE    ; set parameter line offset
1815         mov     ax,cs           ; find where we are loaded
1816         sub     ax,[initseg]    ; find no. of paragraphs available
1817         shl     ax,4            ; convert para. to bytes
1818         add     di,ax
1819         seg     es
1820         cmp     dword ptr CL_HEADER_ID,#0x53726448      ; "HdrS" (reversed)
1821         je      chkver          ; go check header version
1822 mbchain:
1823
1824 ! it must be the chain loader
1825
1826 #ifdef LCF_BDATA
1827         BEG_FS
1828         SEG_FS                  ; suppress BIOS data collection
1829         or      byte ptr par1_prompt+SSDIFF,#FLAG_NOBD  ; suppress BIOS data collection
1830         END_FS
1831 #endif
1832                         ; ES:DI will point at param line (chain.b)
1833         push    ds              ; save DS
1834         mov     ds,[setupseg]   ; point at chain loader(?) header
1835 ; DS points at chain loader
1836         cmp     dword [parC_signature],#EX_MAG_HL ;
1837         jne     not_chain
1838         cmp     word [parC_stage],#STAGE_CHAIN
1839         jne     not_chain
1840         cmp     word [parC_version],#VERSION
1841         jne     not_chain
1842         mov     dx,[parC_drive] ; get drive
1843 ;;;     call    map_device      ; map drive -- uses CS to address "devmap"
1844         mov     [parC_drive],dl ; store mapped drive
1845         mov     [parC_devmap],#devmap   ; save our drive mapping
1846         mov     [parC_devmap+2],cs      ; our DS register
1847 not_chain:
1848         pop     ds
1849         BEG_FS
1850         SEG_FS
1851         mov     dx,[EX_OFF+6]   ; pass DX from first stage
1852         END_FS
1853 #if DEBUG_NEW
1854         mov     bx,#nohdrs
1855         call    say
1856         jmp     cl_wait
1857 #else
1858         br      start_setup2
1859 #endif
1860
1861 chkver:
1862         mov     bh,[gdt+0x1f]           ; check for kernel/initrd conflict
1863         shl     ebx,#8
1864         mov     bx,[gdt+0x1b]           ; form kernel final load address
1865         shl     ebx,#8
1866         mov     eax,[rdbeg]             ; initrd beg address (0 if none)
1867         or      eax,eax
1868         jz      no_overwrite
1869         sub     eax,ebx
1870         jae     no_overwrite
1871         mov     bx,#msg_confl
1872         br      zz
1873
1874 no_overwrite:
1875 #if DEBUG_NEW
1876         mov     bx,#hdr1
1877         call    say
1878         seg     es
1879         mov     ax,CL_HDRS_VERSION
1880         call    wout
1881         mov     bx,#hdr2
1882         call    say
1883         push    di
1884 #endif
1885         seg     es
1886         cmp     word ptr CL_HDRS_VERSION,#NEW_VERSION  ; check for
1887                                 ; new cmdline protocol
1888         jb      protocol201
1889
1890 ! and now the new protocol
1891
1892         mov     ax,es           ; form long address
1893         movzx   edx,ax          ; zero extend segment part to EDX
1894         movzx   edi,di          ; zero extend offset
1895         shl     edx,4           ; make segment into address
1896         add     edx,edi         ; form long absolute address
1897         seg     es
1898         mov     CL_POINTER,edx  ; and pass the address
1899 #if DEBUG_NEW
1900         push    edx             
1901         call    dout
1902         jmp     cl_wait
1903 #else
1904         jmp     start_setup
1905 #endif
1906
1907 ! the old command line passing protocol
1908
1909 protocol201:
1910         seg     es
1911         mov     CL_MAGIC_ADDR,#CL_MAGIC ; set magic number
1912         seg     es
1913         mov     word ptr CL_OFFSET,di
1914 #if DEBUG_NEW
1915         mov     ax,es
1916         call    wout
1917         mov     al,#0x3A        ; issue colon    
1918         call    display
1919         mov     ax,di
1920         call    wout
1921 cl_wait:
1922         mov     bx,#hdr4
1923         call    say
1924         pop     bx
1925         push    ds
1926         push    es
1927         pop     ds
1928         call    strlen
1929         pop     ds
1930         call    wout
1931
1932         call    crlf
1933         call    crlf
1934         jmp     start_setup
1935
1936 #endif
1937 start_setup:                    ; kernel boot comes here
1938 #if DEBUG_NEW
1939         mov     bx,#msg_real
1940 #ifdef LCF_VIRTUAL
1941         call    vmtest
1942         jnc     boot_real_msg_v
1943         mov     bx,#msg_virtual
1944 boot_real_msg_v:
1945 #endif
1946 #ifdef LCF_NOKEYBOARD
1947         call    kbtest
1948         jc      boot_real_msg_k
1949         mov     bx,#msg_no_keyboard
1950 boot_real_msg_k:
1951 #endif
1952         call    say
1953 #endif
1954 #ifdef LCF_BDATA
1955         mov     bx,#msg_bc
1956         call    say
1957         BEG_FS
1958         SEG_FS          ; suppress BIOS data collection?
1959         test    byte ptr par1_prompt+SSDIFF,#FLAG_NOBD  ; suppress?
1960         END_FS
1961         jz      start_setup3
1962         mov     bx,#msg_by
1963         call    say
1964         jmp     start_setup2
1965 start_setup3:
1966
1967 #ifndef LCF_READONLY
1968         or      byte ptr [KEYTABLE+256+mt_flag],#FLAG_NOBD      ; suppress
1969 #if DEBUG_NEW
1970         call    crlf
1971 #endif
1972         call    kt_write
1973 #endif
1974
1975 #if DEBUG_NEW
1976 ;;;     call    pause
1977         mov     ah,#2           ; get keyboard flags
1978         int     0x16
1979         and     al,#0x70        ; Caps, Num, Scroll Lock flags
1980         cmp     al,#0x70
1981         je      near zzz        ; fail with all 3 on
1982 #endif
1983
1984         BEG_FS
1985         SEG_FS
1986         mov     dx,[EX_OFF+6]   ; pass in DX from first stage
1987         END_FS
1988
1989         push    es              ; save ES
1990         call    is_prev_mapper  ; is there a previous mapper
1991         jz      no_remove
1992         seg es
1993           mov   word (di),#0    ; sterilize it
1994 no_remove:
1995         pop     es              ; and restore ES
1996
1997         call    io_biosdata
1998
1999         mov     bx,#msg_s
2000         call    say
2001 #ifndef LCF_READONLY
2002 ; if the BIOS data collection was successful, do not suppress it on future boots
2003         and     byte ptr [KEYTABLE+256+mt_flag],#~FLAG_NOBD     ;  no suppress
2004         call    kt_write
2005 #endif
2006 #endif  /* ifdef LCF_BDATA */
2007
2008 start_setup2:                   ; chain loader boot comes here
2009 #if DEBUG_NEW
2010         call    pause           ; last chance to use the timer
2011 #else
2012         mov     ax,#1500/55     ; about 1.5 second
2013         call    setto           ; set timeout
2014 vpaus1: test    byte ptr timeout,#-1
2015         jz      vpaus1
2016 #endif
2017         call    remto           ; free timer interrupt
2018
2019         push    es              ; is initseg
2020         pop     ds              ; DS = 0x9000 (initseg)
2021 #if 0
2022         push    es
2023         pop     fs
2024         push    es
2025         pop     gs
2026 #endif
2027
2028         add     sp,#SETUP_STACK_DYN     ; increase stack size over this code
2029 if ~*&1                                 ; align to an odd memory location
2030         nop
2031 endif
2032         jmpi    0,SETUPSEG              ; segment part is a variable
2033 setupseg        =       *-2             ;   setupseg is filled in now
2034 initseg:        .word   INITSEG
2035
2036
2037 ! Load one sector (called from load)
2038
2039 doload: pop     bx              ; restore ES:BX
2040         pop     es
2041
2042 ! Load a sequence of sectors, possibly moving into "high memory" (> 1 MB)
2043 ! afterwards.
2044
2045 xread:  push    ax              ; ES == 0 ?
2046         mov     ax,es
2047         or      ax,ax
2048         pop     ax
2049         jz      rdhigh          ; yes -> read into high memory
2050 #ifdef DEBUG
2051         br      sread
2052 #else
2053         jmp     sread
2054 #endif
2055 rdhigh: push    bx              ; okay - DS:BX points to GDT in this case
2056         mov     bx,#LOADSEG     ; adjust ES:BX
2057         mov     es,bx
2058         xor     bx,bx
2059         call    sread           ; load the sector(s)
2060         mov     tempal,al
2061         pop     bx              ; get pointer to GDT
2062         push    ax              ; just in case ...
2063         push    cx
2064         push    si
2065         mov     si,bx           ; turn ES:SI into pointer to GDT
2066         push    ds
2067         pop     es
2068         xor     cx,cx           ; number of words to move
2069         mov     ch,tempal
2070 #ifdef DEBUG
2071         push    si
2072         push    bx
2073         push    cx
2074         mov     al,(si+0x14)
2075         call    bout
2076         mov     ax,(si+0x12)
2077         call    wout
2078         mov     bx,#mov_ar
2079         call    say
2080         mov     ah,(si+0x1f)
2081         mov     al,(si+0x1c)
2082         call    wout
2083         mov     ax,(si+0x1a)
2084         call    wout
2085         mov     bx,#mov_sz
2086         call    say
2087         pop     ax
2088         push    ax
2089         call    wout
2090         call    crlf
2091         pop     cx
2092         pop     bx
2093         pop     si
2094 #endif
2095         push    [gdt+0x1e]
2096         push    bx              ; do the transfer. (save BX, CX and SI because
2097         push    cx              ; we are paranoid)
2098         push    si
2099         mov     ah,#0x87        ; Move Extended Memory Block
2100         int     0x15
2101         pop     si
2102         pop     cx
2103         pop     bx
2104         jc      badmov          ; failed ...
2105         pop     ax              ; check the GDT
2106         cmp     ah,[gdt+0x1f]   ; catch a BIOS that does not handle 386
2107                                 ; addresses (>16Mb)
2108         jne     badmov+1        ; AH error code will be hi byte of address
2109         shr     cx,#8-1         ; convert words to bytes/256
2110         sub     ax,ax           ; put ES back to 0
2111         add     (si+0x1b),cx
2112         adc     (si+0x1f),al
2113         mov     es,ax           ; put ES back to 0
2114         pop     si
2115         pop     cx
2116         pop     ax
2117         ret                     ; done
2118
2119 badmov: pop     bx              ; discard GDT
2120         push    ax              ; save the error code
2121         mov     bx,#msg_bm      ; tell the user ...
2122         jmp     reset           ; (standard procedure calls say & bout)
2123
2124 ! Load a sequence of sectors
2125
2126 sread:  push    bx              ; save registers
2127         push    cx
2128         push    dx
2129         call    cread
2130         mov     di,ax           ; save AL return count
2131         jc      rerror          ; error -> complain
2132         pop     dx              ; restore registers
2133         pop     cx
2134 rokay:  pop     bx
2135         shl     ax,8            ; convert sectors to bytes
2136         add     ah,ah
2137         jc      dowrap          ; loaded an entire segment -> advance ES
2138         add     bx,ax           ; move BX
2139         jnc     nowrap          ; same segment -> go on
2140 dowrap: mov     ax,es           ; move ES
2141         add     ax,#0x1000
2142         mov     es,ax
2143 nowrap:
2144         mov     ax,di           ; restore the block count in AL
2145 aret:   ret                     ; done
2146
2147 ! Read error - try a second time and give up if that fails too
2148
2149 rerror:
2150         push    ax
2151         mov     bx,#msg_re      ; say something
2152 reset:  call    say
2153         pop     ax              ; display the error code
2154         mov     al,ah
2155         call    bout
2156         call    crlf            ; a CR/LF
2157         mov     moff,#0         ; restore initial state
2158 #if DEBUG_NEW
2159         pop     ax
2160         call    swout           ; DX
2161         pop     ax
2162         call    swout           ; CX
2163         pop     ax
2164         call    swout           ; BX
2165         call    crlf
2166 #endif
2167         br      restrt
2168
2169 ! Convert character in AL to upper case
2170
2171 upcase: cmp     al,#0x61        ; lower case character ? ('a')
2172         jb      nolower         ; no -> go on
2173         cmp     al,#0x7a        ; 'z'
2174         ja      nolower
2175         sub     al,#0x20        ; convert to upper case
2176 nolower:ret                     ; done
2177
2178 pause:
2179 #if !DEBUG_NEW
2180         pusha
2181         mov     ax,#3200/55     ; delay 3+ seconds
2182         call    setto
2183 delay1: test    byte ptr timeout,#-1
2184         jz      delay1
2185         popa
2186 #else
2187         pusha
2188         mov     ah,#0x86        ; delay in microseconds
2189         mov     cx,#5<<4        ; 3 seconds; forget DX
2190         int     0x15
2191         popa
2192 #endif
2193         ret
2194
2195
2196
2197 #if DEBUG_NEW
2198
2199 !  display a double word, pushed into the stack
2200
2201 dout:   push    bp
2202         mov     bp,sp
2203         push    ax
2204
2205         mov     ax,(bp+6)       ; get high order
2206         call    wout
2207         mov     ax,(bp+4)       ; get low order
2208         call    wout
2209
2210         pop     ax
2211         leave
2212         ret     4
2213
2214 ! display a space, followed by a word in AX
2215
2216 swout:  push    ax
2217         mov     al,#32
2218         call    display
2219         pop     ax
2220 ; and fall into  wout
2221
2222 ! Display a hexadecimal word/byte/nibble
2223
2224 wout:   push    ax
2225         xchg    al,ah
2226         call    bout
2227         pop     ax
2228 ; must fall into  bout
2229 #endif
2230
2231 bout:   push    ax              ; save byte
2232         shr     al,#4           ; display upper nibble
2233         call    nout
2234         pop     ax
2235 nout:   and     al,#0x0F        ; lower nible only
2236         daa                     ; smaller conversion routine
2237         add     al,#0xF0
2238         adc     al,#0x40        ; AL is hex char [0..9A..F]
2239         jmp     display         ; display it
2240
2241 ! part of the 'say' routine
2242 ! actual entry point is below at 'say:'
2243
2244 say_loop:
2245         cmp     al,#10          ; \n ?
2246         jne     nonl            ; no -> go on
2247         mov     al,#13          ; display a CRLF
2248         call    display
2249         mov     al,#10
2250 nonl:
2251         cmp     al,#12          ; ^L ?
2252         jne     nocls           ; no -> go on
2253 #ifdef MENU
2254         call    menu_form_feed  ; simulate a FF
2255 #else
2256 #ifdef BITMAP
2257         cmp     BYTE [abs_cx+1],#0      ; graphic screen on?
2258         jne     tosnext
2259 #endif
2260         push    bx
2261         mov     ah,#0xf         ; clear the local screen
2262         int     0x10
2263         xor     ah,ah
2264         int     0x10
2265         pop     bx
2266 #endif
2267 tosnext: jmp    snext           ; next character
2268 nocls:  call    display         ; display, tty-style
2269 snext:
2270         inc     bx              ; next one
2271 ! fall into  say                ; process next character
2272
2273 ! Display a NUL-terminated string on the console
2274
2275 say:    mov     al,(bx)         ; get byte
2276         or      al,al           ; NUL ?
2277         jnz     say_loop        ; not the end
2278         ret
2279
2280
2281 ! Display CR/LF
2282
2283 crlf:   mov     al,#13          ; CR
2284         call    display
2285         mov     al,#10          ; LF
2286 ;;;     jmp     display
2287 ; fall into  display
2288
2289 ! Display one character on the console
2290
2291 display:
2292         push    bx              ; save BX
2293
2294 #ifndef LCF_NOSERIAL
2295         call    serdisp
2296 #endif
2297 #if defined(MENU) || defined(BITMAP)
2298         seg     cs
2299         cmp     word [suppress],#0
2300         jnz     dispret
2301
2302 #ifdef MENU
2303         push    ds
2304
2305         push    cs
2306         pop     ds
2307
2308         push    dx
2309
2310         cmp     byte [abs_cx+1],#0      ; is special scrolling in effect?
2311         je      goshowit        ; jump if no special handling
2312         call    mn_getcursor    ; get cursor pos. in DX
2313         
2314         cmp     al,#8           ; is it BS
2315         jne     scroll1
2316         or      dl,dl           ; at col. 0?
2317         jne     goshowit
2318 ; must simulate a BS
2319         mov     dl,[mn_max_row_col]     ; move to EOL
2320         mov     al,#0x0a        ; change to LF
2321         dec     dh              ; back up first of two lines
2322         jmp     scroll_set      ; set new cursor pos. & ring BEL
2323
2324 scroll1:
2325         cmp     al,#0x0a        ; test for LF / NL
2326         jne     scroll2
2327         cmp     dh,[mn_max_row_col+1]  ; bottom row
2328         jae     scrollit
2329 scroll2:
2330         cmp     al,#0x20        ; printing char?
2331         jb      goshowit
2332         cmp     dx,[mn_max_row_col]     ; bottom corner
2333         jne     goshowit
2334
2335 scrollit:
2336         pusha
2337         mov     ax,#0x601       ; scroll up 1 line
2338         mov     bh,[mn_at_mono]
2339         mov     cx,[abs_cx]
2340         mov     dx,[mn_max_row_col]
2341         int     0x10            ; do the scroll
2342         popa
2343 scroll_set:
2344         dec     dh
2345         call    mn_setcursor    ; set cursor up 1 row
2346 goshowit:
2347         pop     dx
2348
2349         pop     ds
2350 #endif
2351 #endif
2352 #ifndef LCF_NOVGA
2353 ;;;     xor     bh,bh           ; display on screen
2354         mov     bx,#7           ; set color for TEXT interface
2355         mov     ah,#14
2356         int     0x10
2357 #endif
2358 dispret:
2359         pop     bx              ; restore BX
2360         ret
2361
2362
2363 #ifndef LCF_NOSERIAL
2364 serdisp:push    dx              ; wait for space in the send buffer
2365         seg     cs
2366         mov     dx,slbase
2367         or      dx,dx
2368         jz      serret
2369         add     dx,#5
2370         push    ax
2371 serwait:in      al,dx
2372         test    al,#0x10        ; break -> set break flag
2373         jz      nobrk
2374         seg     cs
2375         mov     byte ptr break,#1
2376 nobrk:  test    al,#0x20        ; ready to send ?
2377         jz      serwait         ; no -> wait
2378         sub     dx,#5           ; send the character
2379         pop     ax
2380         out     dx,al
2381 serret: pop     dx              ; done
2382         ret
2383 #endif
2384
2385 ! Get a key (CX = timeout exit)
2386
2387 getkey: ;; BEG_FS
2388 ;;      SEG_FS          ; set the timeout
2389         mov     ax,par2_timeout         ;DSC_OFF-10+SSDIFF
2390 ;;      END_FS
2391         call    setto
2392 gwtkey: mov     ah,#1           ; is a key pressed ?
2393         int     0x16
2394         jnz     gotkey          ; yes -> get it
2395 #ifndef LCF_NOSERIAL
2396         mov     dx,slbase       ; using a serial port ?
2397         or      dx,dx
2398         jz      gnokey          ; no -> wait
2399         add     dx,#5           ; character ready ?
2400         in      al,dx
2401         test    al,#1
2402         jz      gnokey          ; no -> wait
2403         sub     dx,#5           ; get it
2404         in      al,dx
2405         and     al,#0x7f        ; strip 8th bit
2406         jnz     gotch           ; ignore NULs
2407 #endif
2408 gnokey: 
2409 #if defined(MENU) || defined(BITMAP)
2410 #ifdef BITMAP
2411         cmp     byte [abs_cx+1],#0
2412         je      no_timer_display
2413 #endif
2414         call    timer_display
2415 no_timer_display:
2416 #endif
2417         test    byte ptr timeout,#1 ; timed out ?
2418         jz      gwtkey          ; no -> wait
2419         pop     ax              ; discard return address
2420         jmp     cx              ; jump to timeout handler
2421 gotkey: xor     ah,ah           ; read a key
2422         int     0x16
2423         push    bx              ; keyboard translation (preserve BX)
2424         mov     bx,#KEYTABLE
2425         xlatb
2426         pop     bx
2427 gotch:
2428 #ifdef LCF_ONE_SHOT
2429         BEG_FS
2430         SEG_FS          ; always enter prompt ?
2431         test    byte ptr par1_prompt+SSDIFF,#FLAG_PROMPT
2432         END_FS
2433         jz      noosht          ; yes -> do not disable timeout
2434 #endif
2435 ;                       disable timeout
2436         test    byte ptr par2_flag2,#FLAG2_UNATTENDED
2437         jnz     nocancel
2438         mov     word ptr par2_timeout,#0xffff
2439 nocancel:
2440 noosht:
2441         ret                     ; done
2442
2443 ! Shift wait loop (AX = timeout, returns CY set if interrupred)
2444
2445 waitsh: call    setto           ; set timeout
2446 actlp:  mov     ah,#2           ; get shift keys
2447         int     0x16
2448 #if defined(LCF_VIRTUAL) && DEBUG_NEW
2449         and     al,#0x1f        ; anything set ? (except NumLock or CapsLock)
2450 #else
2451         and     al,#0x5f        ; anything set ? (except NumLock)
2452 #endif
2453         jnz     shpress         ; yes -> return with CY set
2454 ; 22.7.1 begin
2455         mov     ah,#1           ; get status
2456         int     0x16
2457         jnz     shpress         ; key pressed
2458 ; 22.7.1 end
2459 #ifndef LCF_NOSERIAL
2460         mov     dx,slbase       ; using a serial port ?
2461         or      dx,dx
2462         jz      acnosp          ; no -> go on
2463         cmp     byte ptr break,#0 ; break received ?
2464         jnz     shpress         ; yes -> return with CY set
2465         add     dx,#5           ; check for pending break
2466         in      al,dx
2467         test    al,#0x10
2468         jnz     shpress         ; break received -> return with CY set
2469 #endif
2470 acnosp: test    byte ptr timeout,#1 ; timed out ?
2471         jz      actlp           ; no -> wait
2472         clc                     ; clear carry
2473         ret                     ; done
2474 shpress:stc                     ; set carry
2475         ret                     ; done
2476
2477 ! Timeout handling
2478
2479 instto: push    ds              ; install the timeout handler
2480         push    #0
2481         pop     ds
2482
2483         cli                     ; no interrupts
2484         mov     eax,[0x1c*4]    ; get the old vector
2485         seg     cs
2486         mov     [int1c_l],eax   ; save H & L parts
2487         mov     [0x1c*4],#tick  ; install new vector
2488         mov     [0x1c*4+2],cs
2489         sti                     ; done
2490         pop     ds
2491         ret
2492
2493 remto:  push    es              ; remove the interrupt handler
2494         push    #0
2495         pop     es
2496
2497         mov     eax,[int1c_l]   ; restore the old vector
2498         seg     es
2499         mov     [0x1c*4],eax    ; **
2500         pop     es
2501         ret
2502
2503 ! AX = ticks, 0xffff = no timeout
2504
2505 setto:  or      ax,ax           ; time out immediately ?
2506         jz      toimmed         ; yes -> do it
2507         cli                     ; set timeout value
2508         mov     cntdown,ax
2509         mov     byte ptr timeout,#0 ; clear timed-out flag
2510         sti                     ; done
2511         ret
2512 toimmed:mov     byte ptr timeout,#0xff ; set the timed-out flag
2513         ret                     ; done
2514
2515 tick:   pushf                   ; save flags
2516         seg     cs              ; no timeout ?
2517         cmp     word ptr cntdown,#0xffff
2518         je      notzro          ; yes -> go on
2519         seg     cs              ; decrement counter
2520         dec     word ptr cntdown
2521         jnz     notzro          ; not zero -> go on
2522         seg     cs              ; set timeout flag
2523         mov     byte ptr timeout,#0xff
2524 notzro:
2525         seg     cs
2526         push    dword [int1c_l]
2527         iret                    ; continue with old interrupt
2528
2529 kt_set:
2530 ;;      BEG_FS
2531 ;;      SEG_FS          ; load the keyboard translation table
2532         mov     cx,par2_keytab          ;MSG_OFF+SSDIFF+7
2533 ;;      SEG_FS
2534         mov     dx,par2_keytab+2                ;MSG_OFF+SSDIFF+9
2535 ;;      SEG_FS
2536         mov     al,par2_keytab+4                ;MSG_OFF+SSDIFF+11
2537 ;;      END_FS
2538         mov     bx,#KEYTABLE
2539         ret
2540
2541 #ifndef LCF_READONLY
2542
2543 ! Sector write; used for the keytable only
2544
2545 kt_write:
2546         push    es
2547         push    ds
2548         pop     es
2549         call    kt_set          ; set for KEYTABLE i/o
2550
2551         BEG_FS
2552         SEG_FS          ; BIOS data collection worked before?
2553         test    byte ptr par1_prompt+SSDIFF,#FLAG_BD_OKAY
2554         END_FS
2555         jnz     kt_nowrite
2556
2557         test    byte ptr [par2_flag2],#FLAG2_EL_TORITO  ; a CD?
2558         jnz     kt_nowrite
2559
2560         call    cwrite
2561 kt_nowrite:
2562         pop     es
2563         ret
2564
2565 ! Sector write; used for the stored command line only
2566
2567 cmd_write:      
2568 ;BEG_FS
2569 ;SEG_FS
2570         mov     cx,mt_dflcmd+KEYTABLE+256
2571 ;SEG_FS
2572         mov     dx,mt_dflcmd+2+KEYTABLE+256
2573 ;SEG_FS
2574         mov     al,mt_dflcmd+4+KEYTABLE+256
2575 ;END_FS
2576 ; fall into cwrite
2577 ;
2578 ;  General sector write
2579 ;
2580 cwrite:
2581 #ifdef FLAG_RAID_NOWRITE
2582         BEG_FS
2583         SEG_FS
2584         test    byte ptr par1_prompt+SSDIFF,#FLAG_RAID_NOWRITE ; no writes?
2585         END_FS
2586         jnz     cwok            ; jump if no writing allowed
2587 #endif
2588         BEG_FS
2589         SEG_FS
2590         test    byte ptr par1_prompt+SSDIFF,#FLAG_RAID  ; is it a RAID write
2591         END_FS
2592         jnz     cmd_raid_wrt
2593
2594         mov     byte ptr (dsk_wrflag),#WR_ENABLE      ; flag write operation
2595         call    cread
2596         mov     byte ptr (dsk_wrflag),#0        ; flag read operation
2597
2598         jnc     cwok            ; no error - return
2599 cnok:
2600         pusha
2601         cmp     ah,#3           ; write protect error
2602         je      cnok3
2603         push    ax              ; save error code in AH
2604         mov     bx,#msg_wrerr
2605         call    say
2606         pop     ax
2607         mov     al,ah           ; error code
2608         call    bout
2609         call    crlf            ; leave space
2610         jmp     cnok5
2611 cnok3:
2612         mov     bx,#msg_wrerr3  ; write protect
2613         call    say
2614 cnok5:
2615         popa
2616         stc                     ; flag error  JRC
2617 cwok:
2618 #if DEBUG_NEW
2619         pushf
2620         call    pause
2621         popf
2622 #endif
2623         ret                     ; done
2624
2625 cmd_raid_wrt:
2626         test    dl,#RAID_REL_FLAG       ; relocation called for?
2627         jnz     crw1
2628         mov     ah,#0x99                ; flag error
2629         jmp     cnok
2630 crw1:
2631         push    si
2632         mov     si,[rmask]              ; get raid physical device mask
2633 cwrm = LINEAR_FLAG|LBA32_FLAG|LBA32_NOCOUNT|RAID_REL_FLAG|0X80
2634         and     dl,#cwrm                ; save flags, set device to 80
2635
2636 cwr2:   shr     si,#1
2637         jnc     cwr3
2638         pusha
2639         mov     byte ptr (dsk_wrflag),#WR_ENABLE      ; flag write operation
2640         call    cread_physical          ; read the PHYSICAL device #
2641         mov     byte ptr (dsk_wrflag),#0        ; flag read operation
2642         popa
2643
2644 cwr3:   inc     dx
2645         or      si,si           ; clears the carry
2646         jnz     cwr2
2647
2648         pop     si
2649 ;;;     clc                     ; signal no error
2650         jmp     cwok
2651
2652 cwr_cnt:        .byte   0       ; device code count
2653 cwr_flags:      .byte   0       ; saved flags
2654
2655 #endif
2656
2657 kt_read:                ; KEYTABLE read
2658         call    kt_set          ; set for KEYTABLE i/o
2659         call    cread
2660         jc      keyerr
2661         mov     si,#KEYTABLE    ; compute a checksum of the keytable
2662         mov     di,#SECTOR_SIZE - 8     ; skip the last 4+4 bytes
2663         push    dword #CRC_POLY1
2664         call    crc32
2665         add     di,si
2666         cmp     eax,dword (di)
2667         jz      nokeyerr
2668
2669 ! Checksum error
2670 keyerr:
2671         mov     bx,#msg_chkkey
2672         br      zz              ; go wait
2673 nokeyerr:
2674         ret
2675
2676 ! Sector read
2677 !  enter with AL, CX, DX, ES, BX set for read
2678 !  trashes CX and DI
2679 !
2680 cread:                  ; entry point for mapped device r/w
2681         call    map_device      ; DL (logical) -> DL (physical)
2682
2683 cread_physical:         ; same entry, device is not mapped
2684
2685         test    dl,#LINEAR_FLAG|LBA32_FLAG
2686         jnz     use_linear
2687
2688         push    ax              ;save the count
2689         mov     ah,#2           ;read command
2690         call    dsk_do_rw       ; int 0x13 with retries
2691         pop     cx              ;Carry Set means error on read
2692         mov     al,cl           ;count in AL, error code in AH
2693         ret
2694
2695 use_linear:
2696         mov     ah,hinib        ;will be zero for LINEAR
2697         xchg    al,dh           ;AX is possible address 
2698         test    dl,#LBA32_FLAG  ;test for LBA32/LINEAR  *****
2699         jz      lnread          ;pure LINEAR            *****
2700         test    dl,#LBA32_NOCOUNT
2701         jz      lnread
2702         mov     ah,dh           ;former count is really hi-nibble
2703         mov     hinib,ah
2704         mov     dh,#1           ;set count to 1
2705 lnread:
2706         xchg    di,ax           ;hi-address to DI
2707         mov     al,dh           ;count to AL
2708
2709         test    dl,#RAID_REL_FLAG               ; ******
2710         jz      ln_do_read                      ; ******
2711
2712         call    translate               ; in volume.S
2713
2714 ln_do_read:
2715         call    lba_read
2716         mov     al,cl           ;count returned in AL, error code in AH
2717         ret                     ;Carry Set means error on read
2718
2719 #ifdef LCF_VIRTUAL
2720 ; vmtest -- return Carry=1 if in virtual (VMware) mode
2721 ;           return Carry=0 if in real mode
2722 ;
2723 vmtest:
2724 #ifndef LCF_SUSPEND
2725         pushad                  ; save all extended registers
2726         smsw    ax
2727         rcr     al,1            ; PE bit in AL to Carry
2728         jc      vm_ret          ; exit if virtual mode
2729 #if DEBUG_NEW
2730         mov     ah,#2           ; get keyboard flags
2731         int     0x16
2732         and     al,#0x50        ; Caps, Scroll Lock flags
2733         cmp     al,#0x40
2734         je      vm_vir          ; Caps only means virtual boot simulated
2735 #endif
2736 ;
2737 ;  If no vmdefault, vmdisable, or vmwarn keywords were used, then we do not
2738 ;  care about virtual mode.  Do not touch the hardware, and always return
2739 ;  Carry=0.
2740 ;
2741         test    byte ptr [par2_flag2],#FLAG2_VIRTUAL    ; any vmXXX keywords?
2742         jz      vm_ret          ; TEST clears the carry, always
2743 ;
2744 ;  VMware(R) test for virtual mode
2745 ;
2746         mov     eax,#0x564D5868 ; EAX: in = 'VMXh'   out = version
2747         xor     ebx,ebx         ; EBX:               out = 'VMXh' under vmware
2748         mov     edi,eax
2749         mov     dx,#0x5658      ;  DX: in = 'VX'
2750         mov     ecx,#10         ; ECX: in = VMXGetVersion
2751         in      eax,dx
2752         cmp     ebx,edi         ; test for vmware
2753         clc                     ; NOT vmware if Carry==0
2754         jne     vm_ret          ; not vmware
2755
2756         inc     eax             ; carry is not affected by INC
2757         jz      vm_ret          ; invalid version number == 0xFFFFFFFF
2758
2759 vm_vir:
2760         stc                     ; signal virtual mode
2761
2762 vm_ret: popad           ; restore all the extended registers
2763         ret
2764
2765 #else   /* LCF_SUSPEND changes the interpretation of "virtual" */
2766         pusha
2767         push    es
2768         test    byte ptr [vm_cache],#0xFF       ; test cached value
2769         jnz     vm_ret
2770
2771         mov     byte ptr [vm_cache],#2          ; not virtual
2772
2773         push    ds
2774         pop     es              ; ES:BX
2775         mov     bx,#MAP         ; use this buffer
2776         mov     cx,#1           ; sector 1
2777         mov     dx,#0x80        ; dos C: drive
2778         mov     al,cl           ; 1 sector
2779         call    cread           ;
2780         jc      vm_ret          ; not virtual if error
2781
2782         mov     cx,#PARTITION_ENTRIES           ; count 4 PT entries
2783         lea     bx,[PART_TABLE_OFFSET](bx)      ; first partition entry
2784 vm_pt1:
2785         test    byte ptr (bx),#0x80             ; active
2786         jz      vm_pt2
2787         cmp     byte ptr (bx+4),#LCF_SUSPEND    ; suspend partition
2788         jne     vm_pt2
2789         mov     byte ptr [vm_cache],#1          ; suspend is active
2790 vm_pt2:
2791         lea     bx,[PARTITION_ENTRY](bx)        ; bump pointer
2792         loop    vm_pt1
2793
2794 vm_ret:
2795         mov     al,[vm_cache]           ; get cached value
2796         shr     al,#1
2797         pop     es
2798         popa
2799         ret
2800
2801 vm_cache:
2802         .byte   0               ; 0=unknown, 1=virtual, 2=non-virtual
2803
2804 #endif  /* LCF_SUSPEND */
2805 #endif  /* LCF_VIRTUAL */
2806
2807
2808 #if LCF_NOKEYBOARD
2809 ; kbtest -- return Carry=1 if IBM PC/AT keyboard is present
2810 ;        -- return Carry=0 if no IBM keyboard is present
2811 ;
2812 kbtest:
2813         push    ax
2814 ;
2815 ;  If neither nokbdefault nor nokbdisable was used, we do not touch
2816 ;  the keyboard hardware.  Always report Carry=1 (keyboard present).
2817 ;
2818         test    byte ptr [par2_flag2],#FLAG2_NOKBD
2819         jz      kbtest8
2820
2821 #if DEBUG_NEW
2822         pusha
2823         mov     bx,#msg_kbtest
2824         call    say             ; tell about keyboard test
2825         popa
2826 #endif
2827     /* mardy */
2828         cli                     ; added 5/17/2006
2829         mov     al,#0xee        ; echo command
2830         out     #0x60,al
2831 wait_kbd_ctrl_ready:
2832         in      al,#0x64
2833         and     al,#0x01
2834         jz      wait_kbd_ctrl_ready  ; read status port while it is not ready
2835         in      al,#0x60
2836         sti                     ; added 5/17/2006
2837         xor     al,#0xee        ; XOR clears the carry
2838         jne     kbtest9
2839                 ; if we got the same byte, the keyboard is attached
2840     /* mardy */
2841 #if DEBUG_NEW
2842         mov     ah,#2           ; get keyboard flags
2843         int     0x16
2844         and     al,#0x20        ; Num Lock flag
2845         jz      kbtest9         ; AND cleared the carry
2846 #endif
2847 kbtest8:
2848         stc             ; flag keyboard present
2849 kbtest9:
2850         pop     ax
2851         ret
2852 #endif  /* LCF_NOKEYBOARD */
2853
2854
2855 #if 1
2856 ; crc32 -- calculate CRC-32 checksum
2857 ;
2858 ;       call:
2859 ;               push    dword #POLYNOMIAL
2860 ;
2861 ;               ES:SI   char string pointer
2862 ;               DI      count of characters
2863 ;
2864 ;               call    crc32
2865 ;
2866 ;    CRC-32 is returned in EAX  or  DX:AX
2867 ;               the arguments are popped from the stack
2868 ;
2869 crc32:
2870                 push    bp
2871                 mov     bp,sp
2872
2873                 push    si
2874                 push    di
2875                 push    bx
2876                 push    cx
2877
2878                 xor     eax,eax         ; initialize CRC
2879                 dec     eax             ; EAX = 0xFFFFFFFF
2880                 inc     di
2881 crc32a:
2882                 dec     di
2883                 jz      crc32d
2884                 mov     cx,#8           ; count 8 bits
2885                 seg es
2886                 mov     bl,(si)         ; get next character
2887                 inc     si
2888 crc32b:         shl     bx,#1           ; get hi bit of char in BH
2889                 shl     eax,#1          ; shift hi bit out of CRC
2890                 adc     bh,#0           ; add carry to BH
2891                 shr     bh,#1           ; put bit in carry
2892                 jnc     crc32c          ; skip the xor
2893                 xor     eax,(bp+4)      ; xor in the polynomial
2894 crc32c:
2895                 loop    crc32b          ; loop back for 8 bits
2896                 jmp     crc32a
2897
2898 crc32d:         
2899                 not     eax             ; finialize CRC
2900
2901                 pop     cx
2902                 pop     bx
2903                 pop     di
2904                 pop     si
2905                 
2906                 leave
2907                 ret     4
2908 #endif
2909 /* ifdef HIGHMEM_MAX */
2910 ; enter with BX == Ramdisk size (in 4k pages)
2911 ;
2912 rd_setup:
2913         push    bx              ; save Ramdisk size in pages
2914         mov     eax,[hma]       ; user specified?
2915         or      eax,eax
2916 #ifdef LCF_INITRDLOW
2917         jnz     rd_have_hma
2918 #else           /* ifndef LCF_INITRDLOW */
2919         jnz     near rd_have_hma
2920         BEG_FS
2921         SEG_FS
2922         test    byte ptr par1_prompt+SSDIFF,#FLAG_LARGEMEM
2923         END_FS
2924         jz      near no_e801
2925
2926 ; try the E820 memory map first
2927         xor     edx,edx                 ; flag nothing found
2928         xor     esi,esi                 ; flag size==0
2929         xor     ebx,ebx
2930         jmp     e8go
2931 e8go2:  or      ebx,ebx                 ; test for end
2932         jz      e8go5
2933 e8go:   push    edx                     ; save best prospect
2934         mov     eax,#0xe820
2935         mov     edx,#0x534d4150 ;'SMAP'
2936         mov     ecx,#20
2937         mov     di,#memmap
2938         int     0x15                    ; get memory map
2939         pop     edx                     ; restore what we have found so far
2940         jc      no_e820
2941         cmp     eax,#0x534d4150 ;'SMAP'
2942         jne     no_e820
2943         cmp     ecx,#20
2944         jne     no_e820
2945 #if 0
2946         mov     eax,memmap      ; get start
2947         mov     ecx,memmap+4    ; get high part
2948         cmp     word memmap+16,#1       ; available?
2949         jne     e8no1                   ; go on to next
2950         or      ecx,ecx
2951         jnz     e8go2
2952         cmp     eax,#0x100000   ; compare to 1Mb
2953         ja      e8go2
2954         add     eax,memmap+8    ; get final address
2955         adc     ecx,memmap+12   ;
2956         shrd    eax,ecx,#10     ; convert to 1k blocks (legacy)
2957         cmp     eax,#4*1024     ; compare to 4Mb
2958         jb      no_e820
2959         xchg    eax,edx         ; save in edx
2960         jmp     e8go2
2961
2962 e8no1:  shrd    eax,ecx,#10     ; convert to 1k blocks
2963         cmp     eax,#1024       ; compare to 1Mb
2964         jb      e8go2           ; loop if too small
2965         cmp     eax,edx         ; check against HMA
2966         jae     e8go2
2967         xchg    eax,edx         ; compensate for buggy BIOS
2968         jmp     e8go2           ; remember in EDX & loop
2969 #else
2970         cmp     word memmap+16,#1       ; available?
2971         jne     e8go2
2972         mov     eax,memmap+4    ; hi part of start
2973         shrd    memmap,eax,#10  ; convert start to 1k
2974         mov     eax,memmap+12   ; hi part of size
2975         shrd    memmap+8,eax,#10 ; convert to 1k
2976         cmp     dword memmap,#1024      ; below 1M
2977         jb      e8go2           ; below 1M, no interest
2978         cmp     esi,memmap+8    ; check size
2979         ja      e8go2           ; want largest
2980         mov     edx,memmap      ; start (in 1k)
2981         mov     esi,memmap+8    ; size (in 1k)
2982         add     edx,esi         ; HMA in 1k
2983         jmp     e8go2
2984 #endif
2985 e8go5:  or      edx,edx         ; find anything?
2986         jz      no_e820
2987         xchg    eax,edx
2988         jmp     rd_have_hma
2989 no_e820:
2990 ; above failed, try the older E801 block count interface
2991         xor     cx,cx           ; some BIOSs are buggy
2992         xor     dx,dx
2993         mov     ax,#0xe801      ; call
2994         stc
2995         int     0x15
2996         jc      no_e801
2997         or      cx,cx
2998         jz      e801cx
2999         mov     ax,cx
3000 e801cx: or      dx,dx
3001         jz      e801dx
3002         mov     bx,dx
3003 e801dx: 
3004         movzx   ebx,bx
3005         movzx   eax,ax
3006         shl     ebx,#6          ; convert 64k to 1k
3007         mov     ecx,#16*1024
3008         cmp     eax,ebx         ; compare sizes
3009         ja      e801eax
3010         add     ebx,ecx         ; add in 16M
3011         mov     eax,ebx         ; and use this value
3012         jmp     rd_have_hma
3013 e801eax:
3014         add     eax,#1024       ; add 1M
3015         cmp     eax,ecx         ; is it 16M
3016         jne     rd_have_hma
3017         add     eax,ebx         ; add in ebx
3018         jmp     rd_have_hma
3019 #endif  /* ifndef LCF_INITRDLOW */
3020 no_e801:
3021 ; above two methods failed, try the old 0x88 function
3022         mov     ah,#0x88        ; get count of extended memory blocks
3023         int     0x15
3024         movzx   eax,ax          ; extend to dword
3025         add     eax,#1024       ; add in base 1M
3026 ;
3027 rd_have_hma:    ; have the HMA / 1k in EAX
3028 #if DEBUG_NEW
3029         push    eax
3030         shl     eax,10          ; convert to address
3031         push    eax
3032         call    crlf
3033         call    dout            ; pops its argument
3034         mov     bx,#msg_hma
3035         call    say
3036         pop     eax
3037 #endif
3038         mov     ebx,#15*1024    ; 15Mb
3039         cmp     eax,ebx         ; compare to 15M
3040         jbe     rd_use_eax      ; use lower value
3041         BEG_FS
3042         SEG_FS
3043         test    byte ptr par1_prompt+SSDIFF,#FLAG_LARGEMEM
3044         END_FS
3045         jnz     large_okay
3046         xchg    eax,ebx         ; limit to 15Mb
3047 large_okay:
3048         mov     ebx,#HIGHMEM_MAX/1024
3049 #ifdef NEW3_HDR_VERSION
3050         push    ds
3051         mov     ds,[initseg]    ; load the original boot sector
3052         cmp     word ptr [CL_HDRS_VERSION],#NEW3_HDR_VERSION
3053         jb      not203
3054         mov     ebx,[CL_RAMDISK_MAX]
3055 #if DEBUG_NEW
3056         pop     cx
3057         push    cx
3058         mov     ds,cx
3059         pushad
3060         push    ebx
3061         mov     bx,#hdr3
3062         call    say
3063         call    dout
3064         call    crlf
3065         popad
3066 #endif
3067         dec     ebx
3068         shr     ebx,#10         ; divide by 1024
3069         inc     ebx
3070 not203:
3071         pop     ds
3072 #endif  /* ifdef NEW3_HDR_VERSION */
3073         cmp     eax,ebx
3074         jb      rd_use_eax
3075 ;;;rd_use_smaller:
3076         xchg    eax,ebx         ; must use the smaller
3077 rd_use_eax:
3078         pop     bx              ; get size in pages
3079         shr     eax,2           ; convert to pages
3080         movzx   ebx,bx          ; zero high part of size
3081         sub     eax,ebx         ; start address of ramdisk to EAX
3082 #if DEBUG_INITRD
3083         cmp     dword ptr [hma],#0x180000/1024 ; 1.5Mb
3084         jb      drd_use_eax
3085         cmp     dword ptr [hma],#0xF00000/1024  ; 15Mb
3086         jae     drd_use_eax
3087         mov     eax,[hma]       ; HMA is initrd start
3088         shr     eax,2
3089 drd_use_eax:
3090 #endif
3091 #if 0
3092         cmp     eax,#256        ; we probably need more than 1M for the
3093         ja      rd_okay         ;   kernel to be useful ...
3094         mov     bx,#msg_rd      ; complain
3095 ;;;     call    say             ; is at zz
3096         br      zz              ; and halt 
3097 #else
3098         cmp     eax,#4*256      ; Ramdisk loaded below 4Mb
3099         jae     rd_okay         ;   kernel to be useful ...
3100         mov     bx,#msg_rd4M    ; complain
3101         call    say             ; is at zz
3102 #endif
3103 rd_okay:
3104         shl     eax,4           ; shift (12-8) -> 4
3105         mov     [rdbeg+1],ax    ; set up beginning address
3106         mov     [gdt+0x1b],ax   ; set the GDT for the moves
3107         shr     eax,16          ; get hi-byte of address
3108         mov     [rdbeg+3],al    ; set rest of address
3109         mov     [gdt+0x1f],al   ; and in the GDT, too
3110         ret
3111 /* endif / ifdef HIGHMEM_MAX */
3112
3113
3114 /* enter with SI pointing to DESCRIPTOR 
3115         DS = CS
3116         ES unknown
3117         SI - points at the descriptor
3118 */
3119 load_initrd:
3120         push    [map]
3121         push    [moff]
3122         mov     word ptr [map],#MAP2
3123         push    ds
3124         pop     es
3125         mov     ax,(si+id_flags)        ; get FLAG_TOOBIG, if any
3126 #if FLAG_LARGEMEM!=FLAG_TOOBIG
3127 # error "FLAG_LARGEMEM and FLAG_TOOBIG must be equal"
3128 #endif
3129         and     al,#FLAG_TOOBIG         ; separate flag
3130         BEG_FS
3131         SEG_FS
3132         or      byte ptr par1_prompt+SSDIFF, al ; set FLAG_LARGEMEM
3133         END_FS
3134         add     si,#id_rd_size  ; point at ramdisk size long
3135 ! take care of the RAM disk first
3136         xor     eax,eax
3137         mov     (rdbeg),eax     ; clear address
3138         lodsd
3139         mov     (rdszl),eax     ; set rdszl+rdszh
3140         add     eax,#4095       ; round up &
3141         shr     eax,#12         ; convert to pages
3142         xchg    bx,ax           ; copy to BX
3143         lodsw                   ; address of the first map sector
3144         xchg    cx,ax
3145         lodsw
3146         xchg    dx,ax
3147         lodsb                   
3148         or      bx,bx           ; no RAM disk ?
3149         jz      noramd          ; yes -> skip it 2
3150
3151         push    si              ; save SI, ES, and BX (RD size)
3152         push    es
3153         push    bx
3154         mov     bx,[map]                ; load the first map sector
3155         call    sread
3156         mov     moff,#0
3157 #ifdef DEBUG
3158         mov bx,#stepa
3159         call say
3160 #endif
3161 /* ifdef HIGHMEM_MAX */
3162         pop     bx
3163         call    rd_setup
3164 /* endif */
3165         cmp     dword ptr (rdbeg),#0
3166         je      nordpt          ; no -> no need to patch header for that
3167 ; setrdp:
3168 #if DEBUG_NEW
3169         push    dword (rdbeg)   ; print RAM disk address
3170         mov     bx,#msg_rd2
3171         call    say
3172         call    dout
3173         call    crlf
3174 #endif
3175         mov     es,[setupseg]   ; load the setup codes
3176         mov     eax,(rdbeg)     ; get RAM disk start address
3177         seg     es
3178         mov     (24),eax        ; store in header
3179         mov     eax,rdszl
3180         seg     es
3181         mov     (28),eax        ; set RAM disk size
3182 nordpt: 
3183         push    #0              ; ES=0 is our secret code to load via GDT
3184         pop     es
3185         mov     bx,#gdt
3186         call    lfile           ; load it
3187 #if 1
3188         mov     al,#0x20        ; print a space
3189         call    display
3190 #endif
3191         pop     es              ; restore ES and SI
3192         pop     si
3193 noramd:
3194         pop     [moff]
3195         pop     [map]
3196         ret
3197
3198 #ifndef LCF_NOSERIAL
3199 serLI:  .byte   13,10,0x4c,0x49         ; cr,lf,"LI"
3200
3201 BAUD_BASE = 115200                      ; divisor == 1
3202 divisor:
3203         .byte   BAUD_BASE / 19200       ; must be same as bsect.c table
3204         .byte   BAUD_BASE / 38400
3205         .byte   BAUD_BASE / 57600
3206         .byte   BAUD_BASE / 115200
3207         .byte   BAUD_BASE / 2400
3208         .byte   BAUD_BASE / 2400
3209         .byte   BAUD_BASE / 2400
3210         .byte   BAUD_BASE / 2400
3211
3212 ; serial_setup -- do the setup for the serial line communications
3213 ;
3214 ;       No registers are saved
3215 ;
3216 serial_setup:
3217 ;;      BEG_FS
3218 ;;      SEG_FS
3219         mov     dx,par2_port    ; use a COM port ?
3220                         ; watch out, loads par2_ser_param
3221 ;;      END_FS
3222         dec     dl
3223         js      nocom           ; no -> go on
3224         xor     ax,ax           ; initialize the serial port
3225         xchg    al,dh
3226
3227         push    ax
3228         push    dx
3229
3230 ;;;     or      al,#0x06        ; stop bits = 2, nbits = 7 or 8
3231                                 ; this OR is not needed yet (21.7)
3232         int     0x14            ; Communications Port INIT
3233
3234         push    #0x40
3235         pop     ds
3236
3237         pop     bx              ; was DX
3238
3239         shl     bx,#1
3240         mov     dx,(bx)         ; get the port address from the BIOS
3241
3242         seg     cs              ; keep it
3243         mov     slbase,dx
3244
3245         pop     bx              ; special baud rate test -- was AX
3246
3247         test    bl,#0x04                ; stop bits == 2?
3248         cli                     ; do not disturb any code below
3249         jz      stdbps          ; standard BPS
3250
3251         shr     bx,#5           ; index divisor array
3252         seg     cs
3253         mov     bl,divisor(bx)
3254
3255 spcbps:                         ; CLI: do not disturb ...
3256         push    dx              ; save base address
3257         add     dx,#3           ; enable divisor latch access
3258         in      al,dx
3259         or      al,#0x80
3260         out     dx,al
3261         pop     dx              ; set new divisor
3262         push    dx
3263         xchg    ax,bx
3264         out     dx,al
3265         inc     dx
3266         mov     al,ah
3267         out     dx,al
3268         inc     dx              ; disable divisor latch access
3269         inc     dx
3270         xchg    ax,bx
3271         and     al,#0x7f
3272         out     dx,al
3273         pop     dx              ; restore base address
3274
3275 stdbps:                         ; CLI: redundant if fell in from above
3276         push    dx
3277         add     dx,#4           ; address Modem Control Reg.
3278 #if 0
3279         in      al,dx
3280         or      al,#3           ; turn on DTR and RTS
3281 #else
3282         mov     al,#3           ; turn on DTR and RTS
3283 #endif
3284         out     dx,al
3285         pop     dx
3286         sti                     ; done
3287         
3288         mov     cx,#32          ; drain the queue (if any)
3289 drain:  in      al,dx
3290         loop    drain
3291         add     dx,#5           ; clear the status register
3292         in      al,dx
3293
3294     ; send "\r\nLI" to the serial port
3295
3296         mov     si,#serLI
3297         mov     cx,#4
3298 ser1:   seg     cs
3299         lodsb
3300         call    serdisp
3301         loop    ser1
3302
3303 nocom:
3304         ret
3305
3306 #endif          /* LCF_NOSERIAL */
3307
3308
3309
3310 #ifdef SHS_PASSWORDS
3311 #include "shs3.S"
3312 #endif
3313 #include "read.S"
3314 #include "volume.S"
3315 #define SECOND_STAGE_LOADER
3316 #include "mapper.S"
3317 #undef SECOND_STAGE_LOADER
3318 #ifdef LCF_BDATA
3319 #include "bdata.h"
3320 #include "biosdata.S"
3321 #endif
3322 #if defined(MENU) || defined(BITMAP) || DEBUG_NEW
3323 #include "strlen.S"
3324 #endif
3325 #ifdef MENU
3326 #include "graph.S"
3327 #include "menu.S"
3328 #include "crt.S"
3329 #endif
3330 #ifdef BITMAP
3331 #include "bitmap.S"
3332 #include "vesainfo.h"
3333 #include "display4.S"
3334 #endif
3335
3336 ! Put tokens into keyboard buffer
3337
3338 putkbd: add     si,#4           ; skip over "kbd="
3339         push    es
3340         xor     ax,ax           ; set ES to zero
3341         mov     es,ax
3342 pknext: lodsb                   ; get next byte
3343         or      al,al           ; NUL ?
3344         jz      pkdone          ; yes -> done
3345         cmp     al,#32          ; blank ?
3346         jne     pkrd            ; no -> read scan code
3347 pkdone: dec     si              ; return last character
3348         pop     es              ; done
3349         ret
3350 pkrd:   xor     cx,cx           ; clear accumulator
3351 pkrdlp: cmp     al,#97          ; lower case character ?
3352         jb      pknol           ; no -> go on
3353         sub     al,#32          ; make upper case
3354 pknol:  sub     al,#48          ; normalize
3355         cmp     al,#10          ; >"9" ?
3356         jb      pkok            ; no -> okay
3357         cmp     al,#17          ; <"A" ?
3358         jb      pksyn           ; yes -> syntax error
3359         sub     al,#7           ; adjust
3360         cmp     al,#16          ; >"F" ?
3361         jae     pksyn           ; yes -> syntax error
3362 pkok:   shl     cx,1            ; shift CX
3363         jc      pksyn           ; carry means trouble
3364         shl     cx,1
3365         jc      pksyn
3366         shl     cx,1
3367         jc      pksyn
3368         shl     cx,1
3369         jc      pksyn
3370         add     cl,al           ; put in lowest nibble
3371         lodsb                   ; get next byte
3372         or      al,al           ; NUL ?
3373         jz      pkend           ; yes -> at end
3374         cmp     al,#32          ; space ?
3375         je      pkend           ; yes -> at end
3376         cmp     al,#44          ; comma ?
3377         je      pkmore          ; yes -> end of token
3378         jmp     pkrdlp          ; token continues
3379 pksyn:  mov     bx,#msg_pks     ; complain
3380         call    say
3381 pkfls:  lodsb                   ; flush to end of option
3382         or      al,al
3383         jz      pkdone
3384         cmp     al,#32
3385         je      pkdone
3386         jmp     pkfls
3387 pkend:  call    pkput           ; store token
3388         jmp     pkdone          ; ... and return
3389 pkmore: call    pkput           ; store token
3390         jmp     pknext          ; handle next token
3391 pkput:  seg     es              ; get buffer pointer
3392         mov     bx,[KBEND]
3393         mov     dx,bx
3394         add     dx,#2           ; increment it
3395         cmp     dx,#KBHIGH      ; (wrap around end)
3396         jb      pknadj
3397         mov     dx,#KBLOW
3398 pknadj: seg     es              ; buffer full ?
3399         cmp     dx,[KBBEG]
3400         je      pkfull          ; yes -> error
3401         seg     es              ; store scan code
3402         mov     (bx+0x400),cx
3403         seg     es              ; store new pointer
3404         mov     [KBEND],dx
3405         ret                     ; done
3406 pkfull: mov     bx,#msg_pkf     ; complain
3407         call    say
3408         pop     ax              ; discard return address
3409         jmp     pkfls           ; abort
3410
3411 ! Set VGA mode
3412
3413 setvga: add     si,#4           ; skip over "vga="
3414         push    si              ; save SI
3415         mov     bx,#vgatab      ; scan VGA table
3416 svgatb: pop     si              ; get pointer to option value
3417         push    si
3418         mov     cx,(bx)         ; get VGA code
3419         or      cx,cx           ; at end ?
3420         jz      vganum          ; yes -> must be numeric
3421         inc     bx              ; compare the strings
3422         inc     bx
3423 vgacmp: lodsb
3424         call    upcase          ; (case-insensitive)
3425         mov     ah,(bx)
3426         inc     bx
3427         or      ah,ah           ; at end ?
3428         jnz     vgamore         ; no -> go on
3429         or      al,al           ; at end of line ?
3430         jz      vgafnd          ; yes -> found it
3431         cmp     al,#32          ; space ?
3432         je      vgafnd          ; yes -> found it
3433         jmp     svgatb          ; try next entry otherwise
3434 vgamore:cmp     al,ah
3435         je      vgacmp          ; equal -> next character
3436 vgaskp: mov     al,(bx)         ; skip to end of reference string
3437         inc     bx
3438         or      al,al
3439         jnz     vgaskp
3440         jmp     svgatb          ; try next entry
3441 vgafnd: pop     ax              ; drop SI
3442
3443 vgaput: dec     si              ; read last character again
3444 vgaput1: mov    vgaovr,cx       ; set VGA mode
3445         clc                     ; okay, done
3446         ret
3447
3448 vganum: pop     si              ; get SI
3449 #if 1
3450         call    strtoul
3451         jc      vgaerr
3452         mov     cx,ax
3453         or      dx,dx
3454         jnz     vgaerr
3455         jmp     vgaput1
3456 #else
3457         xor     cx,cx
3458         mov     ah,cl
3459         test    byte ptr (si),#0xff ; no value ?
3460         jz      vgaerr          ; yes -> error
3461 vgadig: lodsb                   ; get the next character
3462         or      al,al           ; at end ?
3463         jz      vgaput          ; yes -> done
3464         cmp     al,#32
3465         je      vgaput
3466         cmp     al,#48          ; is it a digit ?  (0x30=48="0")
3467         jb      vgaerr          ; no -> error
3468         cmp     al,#57          ; 57=0x39="9"
3469         ja      vgaerr
3470         sub     al,#48          ; cx = cx*10+al-'0'
3471         imul    cx,#10
3472         add     cx,ax
3473         jnc     vgadig          ; next one
3474 #endif
3475
3476 vgaerr: mov     bx,#msg_v       ; display an error message
3477         call    say
3478 /* ifdef HIGHMEM_MAX */
3479         xor     eax,eax
3480         mov     dword ptr [hma],eax
3481 /* endif */
3482         stc                     ; return an error
3483         ret
3484
3485 vgatab:
3486 #ifdef NORMAL_VGA
3487         .word   ASK_VGA
3488         .ascii  "ASK"
3489         .byte   0
3490         .word   EXTENDED_VGA
3491         .ascii  "EXTENDED"
3492         .byte   0
3493         .word   EXTENDED_VGA
3494         .ascii  "EXT"
3495         .byte   0
3496         .word   NORMAL_VGA
3497         .ascii  "NORMAL"
3498         .byte   0
3499 #endif
3500         .word   0
3501
3502
3503 ! get numeric string suffixed with "KkMmGg"
3504 ! updates SI
3505
3506 get_K:
3507         push    cx              ; save CX
3508
3509         call    strtoull        ; get number in DX:AX
3510         jc      gmthis2         ; signal conversion error
3511
3512         mov     bl,(si)         ; get next character
3513         or      bl,#0x20        ; convert to lower case
3514         cmp     bl,#0x6b        ; 'K' or 'k' ?
3515         je      gmthis          ; yes -> do not change
3516 #if 1
3517         mov     cx,#20          ; divide or multiply by 2^20
3518         cmp     bl,#0x67        ; 'G' or 'g' ?
3519         je      gmmul
3520 #endif
3521         mov     cx,#10          ; divide or multiply by 2^10
3522         cmp     bl,#0x6d        ; 'M' or 'm' ?
3523         je      gmmul
3524
3525 ! no Suffix
3526         dec     si              ; will increment later
3527         
3528 gmdivl:
3529         shr     eax,cl          ; shift by CL
3530         jmp     gmthis          ; done
3531 gmmul:
3532 gmmull:
3533         shl     eax,1           ; shift by 1 each time
3534         jc      gmvbig          ; very big if overflow
3535         loop    gmmull          ; ten times
3536
3537 ! exit with no error
3538
3539 gmthis:
3540         inc     si
3541         clc                     ; signal no error
3542 gmthis2:
3543         mov     bl,(si)         ; next character to BL
3544 #if 0
3545         jc      gmdebug1
3546         pushad
3547         push    eax
3548         call    dout
3549         mov     bx,#msg_gk
3550         call    say
3551         popad
3552 gmdebug1:
3553 #endif
3554         pop     cx              ; restore register
3555         ret
3556
3557 gmvbig:
3558         mov     eax,#HIGHMEM_MAX/1024
3559         jmp     gmthis
3560
3561
3562 ! Set memory limit
3563
3564 getmem:
3565         push    si              ; save SI for copying
3566         add     si,#4           ; advance to number?
3567         call    get_K
3568         jc      gmcopy          ; error, just copy it
3569
3570         cmp     bl,#0x40        ; is it '@'
3571         jne     gm22
3572 ! <size>@<start> format (2.4 kernels)
3573         push    eax             ; save size
3574         inc     si              ; skip '@'
3575         call    get_K
3576         pop     edx             ; restore size
3577         jc      memerr
3578         cmp     eax,#1024       ; start : 1meg
3579         ja      gmcopy          ; just copy if above
3580         add     eax,edx         ; EAX = hma/1024
3581         cmp     eax,#2048       ; high : 2meg
3582         jbe     gmcopy
3583 gm22:
3584         or      bl,#0x20
3585         cmp     bl,#0x20        ; NUL or SPACE
3586 #if 0
3587         jne     memerr
3588 #else
3589         jne     gmcopy          ; allow <size>#<start> and <size>$<start>
3590 #endif
3591         cmp     dword ptr [hma],#0      ; set already?
3592         jne     gmnocopy
3593         mov     dword ptr [hma],eax     ; set it        
3594 gmcopy: pop     si
3595 gmret:  ret
3596 gmnocopy:  pop  bx
3597         ret
3598
3599
3600 memerr:
3601         mov     bx,#msg_me      ; numeric conversion error
3602         call    say
3603         br      restrt
3604
3605 strtoull:                       ; numeric conversion to EAX
3606         call    strtoul
3607         push    dx
3608         push    ax
3609         pop     eax
3610         ret
3611
3612 strtoul:          /* string to unsigned long in DX:AX */
3613         xor     ax,ax
3614         xor     dx,dx
3615         mov     cx,#10          ; default radix is decimal
3616         cmp     byte ptr (si),#0x39
3617         ja      s2lbad          ; error if > '9'
3618         cmp     byte ptr (si),#0x30        ; == '0'?
3619         jb      s2lbad          ; error if < '0'
3620         jne     s2lnext
3621         inc     si
3622         dec     cx
3623         dec     cx              ; assume octal : CX = 8
3624         
3625         cmp     byte ptr (si),#0x58        ; == 'X'?
3626         je      s2lhex
3627         cmp     byte ptr (si),#0x78        ; == 'x'?
3628         jne     s2lnext
3629 s2lhex: add     cx,cx           ; it is hexadecimal
3630         inc     si
3631 s2lnext:
3632         xor     bx,bx
3633         mov     bl,(si)         ; get next character
3634
3635         or      bl,#0x20        ; convert to lower case
3636         sub     bl,#0x30        ; - '0'
3637         jb      s2ldone
3638         cmp     bl,cl           ; compare to radix
3639         jb      s2lmul
3640         add     bl,#0x30-0x61+10
3641         cmp     bl,cl           ; compare to radix
3642         jnb     s2ldone
3643 s2lmul:
3644         push    dx              ; save high order
3645         mul     cx              ; multiply by radix
3646         add     ax,bx
3647         adc     dx,#0           ; carry possible only in radix 10
3648         pop     bx
3649         push    dx
3650         xchg    ax,bx
3651         mul     cx
3652         or      dx,dx
3653         jnz     s2lbad
3654         pop     dx
3655         add     dx,ax
3656         jc      s2lbad
3657         xchg    ax,bx
3658         inc     si
3659         jmp     s2lnext
3660
3661 s2lbad: 
3662         stc
3663         ret
3664         
3665 s2ldone:
3666         clc 
3667         ret
3668
3669 /* new 22.7 */
3670 ; find_image
3671 ;       if there is something on the command line
3672 ;       return the image number it selects
3673 ;
3674 ;       enter with:
3675 ;               nothing
3676 ;       exit with:
3677 ;               If nothing selected:
3678 ;                   Carry Clear
3679 ;                   AX==0
3680 ;               If an image is selected:
3681 ;               (fuzzy selection or exact selection)
3682 ;                   Carry SET
3683 ;                   AX==#image
3684 ;                   BX==pointer to descriptor
3685 ;                   
3686 ;
3687 ;       side effect:
3688 ;               The selected image is hi-lited if the menu is displayed
3689 ;
3690 find_image:
3691         push    cx
3692         push    si
3693         push    di
3694         
3695         mov     cx,#IMAGES      ; test all names
3696         mov     si,#DESCR0
3697         xor     bx,bx           ; clear BX
3698         push    si
3699
3700 fi_nextn:
3701         mov     di,#cmdline
3702         test    byte ptr (si),#0xFF     ; null descriptor at end
3703         jz      fi_nomore
3704
3705 fi_nextc:
3706         mov     al,(si)         ; get next character in descr
3707         inc     si
3708 #ifdef LCF_IGNORECASE
3709         call    upcase
3710 #endif
3711         mov     ah,al
3712         mov     al,(di)         ; get next char in cmdline
3713         inc     di
3714 #ifdef LCF_IGNORECASE
3715         call    upcase
3716 #endif
3717         or      al,al           ; NUL in command line
3718         je      fi_pmat
3719         cmp     al,#32          ; SPACE in command line
3720         jne     fi_cmp
3721
3722 ; have partial match, set BX conditionally
3723 fi_pmat:
3724         or      ah,ah           ; NUL in descriptor name
3725         jz      fi_found        ; EXACT match found
3726
3727         test    byte ptr par2_flag2,#FLAG2_UNATTENDED   ; (22.7)
3728         jnz     fi_skipn        ; no partial match if unattended
3729
3730         or      bx,bx
3731         jnz     fi_skipn        ; already set
3732         pop     bx
3733         push    bx
3734         jmp     fi_skipn        ; go to next
3735
3736 fi_cmp:
3737         cmp     al,ah           ; character equal ?
3738         je      fi_nextc        ; compare next character
3739
3740 ; advance to next descriptor
3741 fi_skipn:
3742         pop     si
3743         add     si,#id_size     ; test next name
3744         push    si
3745         loop    fi_nextn
3746
3747 fi_nomore:
3748         pop     si
3749         or      bx,bx           ; fuzzy match?
3750         jnz     fi_fuzzy
3751
3752 #if defined(MENU) || defined(BITMAP)
3753         mov     ax,[dimage]
3754         call    lowlite         ; no match, nothing hi-lited
3755 ;;;     mov     word [dimage],#0
3756 #endif
3757         xor     ax,ax           ; clears the carry
3758 fi_exit:
3759         pop     di
3760         pop     si
3761         pop     cx
3762         ret
3763         
3764 fi_found:
3765         pop     bx              ; BX is matched descriptor
3766 fi_fuzzy:
3767         mov     ax,bx
3768         sub     ax,#DESCR0
3769         mov     cl,#id_size
3770         div     cl
3771         cbw
3772 #if defined(MENU) || defined(BITMAP)
3773         mov     di,[dimage]
3774         mov     [dimage],ax
3775         cmp     byte [abs_cx+1],#0      ; see if menu is displayed
3776         je      fi_nochange
3777         cmp     ax,di
3778         je      fi_nochange2
3779         xchg    ax,di
3780         call    lowlite
3781         xchg    ax,di
3782 fi_nochange2:
3783         call    hilite
3784 fi_nochange:
3785 #endif
3786         stc
3787         jmp     fi_exit
3788 /* end new 22.7 */
3789
3790 #if DEBUG_NEW
3791 ; check that nobody has changed the FS register
3792 fs_check:
3793         push    ax
3794         mov     ax,fs
3795         seg cs
3796         cmp     ax,[firstseg]
3797         je      fs_check_okay
3798 ; oops, somebody changed it !!!
3799         pop     ax      ; restore
3800         pop     ax      ; get return
3801         push    cs
3802         pop     ds
3803         sub     ax,#3   ; length of call
3804         call    wout
3805         mov     bx,#msg_fs_changed
3806         br      zz
3807 fs_check_okay:
3808 #if CHECK_FS_VERBOSE
3809         pusha
3810         mov     bp,sp
3811         mov     ax,16+2(bp)
3812         sub     ax,#3
3813         call    wout
3814         mov     bx,#msg_fs_okay
3815         push    ds
3816         push    cs
3817         pop     ds
3818         call    say
3819         pop     ds
3820         popa
3821 #endif
3822 fs_check_ret:
3823         pop     ax
3824         ret
3825 msg_fs_changed:
3826         .ascii  " <- loc where FS is clobbered\n"
3827         .byte   0
3828 #if CHECK_FS_VERBOSE
3829 msg_fs_okay:
3830         .ascii  " <- FS okay\n"
3831         .byte   0
3832 #endif
3833 #endif
3834
3835 ! Some messages
3836
3837 msg_p:  .ascii  "boot: "
3838         .byte   0
3839
3840 msg_l:  .ascii  "Loading "
3841         .byte   0
3842
3843 msg_bc: .ascii  "BIOS data check "
3844         .byte   0
3845
3846 msg_s:  .ascii  "successful\n"
3847         .byte   0
3848
3849 msg_by: .ascii  "bypassed\n"
3850         .byte   0
3851
3852 msg_re: .byte   10
3853         .ascii  "Error 0x"
3854         .byte   0
3855
3856 msg_nf: .ascii  "No such image. [Tab] shows a list."
3857         .byte   10,0
3858
3859 msg_time:
3860         .ascii  "O - Timestamp mismatch\n"
3861         .byte   0
3862
3863 msg_chkerr:
3864         .ascii  "O - Descriptor checksum error\n"
3865         .byte   0
3866
3867 msg_chkkey:
3868         .ascii  "O - Keytable read/checksum error\n"
3869         .byte   0
3870
3871 msg_confl:
3872         .ascii  "Kernel and Initrd memory conflict\n"
3873         .byte   0
3874
3875 msg_sigerr:
3876         .ascii  "O - Signature not found\n"
3877         .byte   0
3878
3879 msg_me: .byte   10
3880         .ascii  "vga/mem=  requires a numeric value"
3881         .byte   10,0
3882
3883 msg_wrerr:      .ascii  "\nMap file write; BIOS error code = 0x"
3884         .byte   0
3885
3886 msg_wrerr3:     .ascii  "\nMap file: WRITE PROTECT\n"
3887         .byte   0
3888
3889 #ifdef MEMORY_CHECK
3890 msg_mem: .ascii "EBDA is big; kernel setup stack overlaps LILO second stage"
3891         .byte   10,0
3892 #endif
3893
3894 #ifdef LCF_VIRTUAL
3895 msg_vmwarn:
3896         .ascii  "WARNING:  Booting in Virtual environment\n"
3897         .ascii  "Do you wish to continue? [y/n] "
3898         .byte   0
3899 #endif
3900
3901 #if DEBUG_NEW
3902 sdx:    .ascii  " DX="
3903         .byte   0
3904
3905 msg_pl: .ascii  "\nParameter line = "
3906         .byte   0
3907 #ifdef LCF_NOKEYBOARD
3908 msg_kbtest:
3909         .ascii  "**PC/AT Keyboard test**\n"
3910         .byte   0
3911 #endif
3912
3913 #if defined(LCF_VIRTUAL) || defined(LCF_NOKEYBOARD)
3914 msg_real:
3915         .ascii  "Performing REAL MODE boot\n"
3916         .byte   0
3917
3918 #ifdef LCF_VIRTUAL
3919 msg_virtual:
3920         .ascii  "Performing VIRTUAL MODE boot\n"
3921         .byte   0
3922 #endif
3923 #ifdef LCF_NOKEYBOARD
3924 msg_no_keyboard:
3925         .ascii  "Performing NO KEYBOARD DEFAULT boot\n"
3926         .byte   0
3927 #endif
3928 #endif
3929
3930 msg_where:
3931         .ascii  "\nINIT SETUP CODE SS:SP  EX_OFF_DX 2ndDX\n"
3932         .byte   0
3933
3934 msg_low: .ascii " low"
3935         .byte   0
3936
3937 msg_high:  .ascii " high"
3938         .byte   0
3939
3940 hdr1:   .ascii  "\nHeader 0x"
3941         .byte   0
3942
3943 hdr2:   .ascii  " cmdline at "
3944         .byte   0
3945
3946 hdr4:   .ascii  "   length = 0x"
3947         .byte   0
3948
3949 hdr3:   .ascii  "\nRamdisk_max "
3950         .byte   0
3951
3952 nohdrs: .ascii  "\nNo cmdline passed"
3953         .byte   0
3954
3955 msg_rd2: .byte  10
3956         .ascii  "RAM disk loaded at: "
3957         .byte   0
3958
3959 msg_hma: .ascii " is the HMA\n"
3960         .byte   0
3961
3962 msg_gk: .ascii  " returned by 'get_K'\n"
3963         .byte   0
3964
3965 #endif
3966
3967 msg_int:.byte   10
3968         .ascii  "*Interrupted*"
3969         .byte   10,0
3970
3971 msg_eof:.byte   10
3972         .ascii  "Unexpected EOF"
3973         .byte   10,0
3974
3975 msg_pw: .ascii  "Password: "
3976         .byte   0
3977
3978 msg_pf: .ascii  "Sorry."
3979         .byte   10,0
3980
3981 msg_v:  .byte   10
3982         .ascii  "Valid vga values are ASK, NORMAL, EXTENDED or a "
3983         .ascii  "decimal number."
3984         .byte   10,0
3985
3986 msg_pks:.byte   10
3987         .ascii  "Invalid hexadecimal number. - Ignoring remaining items."
3988         .byte   10,0
3989
3990 msg_pkf:.byte   10
3991         .ascii  "Keyboard buffer is full. - Ignoring remaining items."
3992         .byte   10,0
3993
3994 msg_bm: .byte   10
3995         .ascii  "Block move error 0x"
3996         .byte   0
3997
3998 #if 0
3999 msg_rd: .byte   10
4000         .ascii  "Not enough memory for RAM disk"
4001         .byte   10,0
4002 #else
4003 msg_rd4M: .byte 10
4004         .ascii  "Initial ramdisk loads below 4Mb; "
4005         .ascii  "kernel overwrite is possible."
4006         .byte   10,0
4007 #endif
4008
4009 ospc:   .ascii  "O"
4010 #ifdef LCF_BEEP
4011         .byte   7
4012 #endif
4013 #ifdef LCF_VERSION
4014         .ascii  " "     
4015         .ascii  SA(VERSION_MAJOR)
4016         .ascii  "."
4017         .ascii  SA(VERSION_MINOR)
4018         .ascii  VERSION_EDIT
4019 #endif
4020         .byte   32,0
4021
4022 bs:     .byte   8,32,8,0
4023
4024 #ifdef DEBUG
4025 stepa:  .ascii  " RAM disk,"
4026         .byte   0
4027 step0:  .ascii  " map page,"
4028         .byte   0
4029 step0b: .ascii  " fallback,"
4030         .byte   0
4031 step1:  .ascii  " options,"
4032         .byte   0
4033 step1b: .ascii  " fallback,"
4034         .byte   0
4035 step2:  .ascii  " boot,"
4036         .byte   0
4037 step3:  .ascii  " setup,"
4038         .byte   0
4039 step4:  .ascii  " system "
4040         .byte   0
4041
4042 sax:    .ascii  "AX="
4043         .byte   0
4044 sbx:    .ascii  " BX="
4045         .byte   0
4046 scx:    .ascii  " CX="
4047         .byte   0
4048 ses:    .ascii  " ES="
4049         .byte   0
4050 sdone:  .byte   10
4051         .byte   0
4052
4053 mov_ar: .ascii  " -> "
4054         .byte   0
4055 mov_sz: .ascii  ", words "
4056         .byte   0
4057 #endif
4058
4059         .even
4060
4061 init_dx:        .word   0
4062
4063 #if defined(MENU) || defined(BITMAP)
4064 suppress:.word  0               ; suppress console output (MUST be word)
4065 #endif
4066 hinib:  .byte   0               ; hi-nibble of address
4067 tempal: .byte   0
4068 moff:   .word   0               ; map offset
4069 map:    .word   MAP             ; map to use
4070
4071 cntdown:.word   0               ; count-down
4072 timeout:.byte   0               ; timed out
4073
4074 dolock: .byte   0
4075
4076 int1c_l:.word   0               ; old timer interrupt
4077 int1c_h:.word   0
4078
4079 old_del:.word   0               ; delay before booting
4080
4081 nodfl:  .word   0               ; action if no defaults are present
4082
4083 #ifndef LCF_NOSERIAL
4084 slbase: .word   0               ; serial port base (or 0 if unused)
4085 break:  .byte   0               ; break received flag
4086 #endif
4087
4088 usrinpm:.byte   UI_MAGIC
4089
4090 cmdbeg: .word   0
4091 options:.word   0
4092
4093 rdbeg:  .word   0,0             ; RAM dist begin address (dword)
4094
4095 rdszl:  .word   0               ; RAM disk size
4096 rdszh:  .word   0
4097
4098 vgaovr: .word   0               ; VGA mode overwrite
4099
4100 /* ifdef HIGHMEM_MAX */
4101 hma:    .word   0,0             ; Highest Memory Address
4102 memmap: .word   0,0,0,0,0,0,0,0,0,0
4103 /* endif */
4104 dskprm: .word   0,0,0,0,0,0
4105
4106         .even                   ; control alignment from here down
4107 acmdbeg:.ascii  "auto "
4108 mcmdbeg:.ascii  "BOOT_IMAGE"
4109 prechr: .byte   32              ; space: guard double blank supression
4110                                 ; equal sign: variable assignment
4111 cmdline:.byte   0
4112
4113 #ifdef BITMAP
4114 _line   =       cmdline+CL_LENGTH               ; must be 640 bytes long
4115 #endif
4116         .org    *+4
4117 theend:
4118
4119 lkwbuf  =       cmdline+CL_LENGTH+2     ; this is a word
4120 lkcbuf  =       lkwbuf+2
4121 theend2 =       lkcbuf+CL_LENGTH        ; lkcbuf is 256
4122
4123 the_end1        = theend+511
4124 theends =       the_end1/512
4125         .org    theends*512-4
4126         .long   X
4127         .align  512
4128 max_secondary:
4129
4130 #if 0
4131 /* the older version 21 layout */
4132 Map             =       max_secondary + SECTOR_SIZE
4133 Dflcmd          =       Map + SECTOR_SIZE
4134 Map2            =       Dflcmd
4135 Descr           =       Dflcmd + SECTOR_SIZE
4136 Keytable        =       Descr + SECTOR_SIZE*MAX_DESCR_SECS_asm
4137 ParmBSS         =       Keytable + SECTOR_SIZE
4138 #else
4139 /* a possible 22.5.6 layout puts the descriptors last */
4140 Map             =       max_secondary + SECTOR_SIZE
4141 Dflcmd          =       Map + SECTOR_SIZE
4142 Map2            =       Dflcmd
4143 Keytable        =       Dflcmd + SECTOR_SIZE
4144 Descr           =       Keytable + SECTOR_SIZE
4145 ParmBSS         =       Descr + SECTOR_SIZE*MAX_DESCR_SECS_asm
4146 #endif
4147
4148 #if COMMAND_LINE_SIZE > 256
4149 BSSstart        =       ParmBSS
4150 Parmline        =       BSSstart + SECTOR_SIZE
4151 #else
4152 Parmline        =       ParmBSS
4153 BSSstart        =       Parmline + CL_LENGTH
4154 #endif
4155
4156 !************************************
4157 !  BSS data:
4158 !     moved from  volume.S 
4159
4160 #define BSS_DATA
4161         .org    BSSstart
4162 #include "volume.S"
4163 #ifdef SHS_PASSWORDS
4164 #include "shs3.S"
4165 #endif
4166
4167         .align  512
4168 BSSend  =       *
4169 BSSsize         =       BSSend-BSSstart
4170
4171
4172 Dataend         =       Parmline + SECTOR_SIZE
4173
4174         .org    max_secondary
4175
4176
4177
4178 #if 0
4179 DESCR0 = DESCR+2
4180 #else
4181 DESCR0 = DESCR
4182 #endif