bec0b7baf8031464f65e7af3da80c314443a2811
[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                    ; circumvented due to BIOS problems
2931         br      no_e801                 ; skip to backup plan
2932 e8go2:  or      ebx,ebx                 ; test for end
2933         jz      e8go5
2934 e8go:   push    edx                     ; save best prospect
2935         mov     eax,#0xe820
2936         mov     edx,#0x534d4150 ;'SMAP'
2937         mov     ecx,#20
2938         mov     di,#memmap
2939         int     0x15                    ; get memory map
2940         pop     edx                     ; restore what we have found so far
2941         jc      no_e820
2942         cmp     eax,#0x534d4150 ;'SMAP'
2943         jne     no_e820
2944         cmp     ecx,#20
2945         jne     no_e820
2946 #if 0
2947         mov     eax,memmap      ; get start
2948         mov     ecx,memmap+4    ; get high part
2949         cmp     word memmap+16,#1       ; available?
2950         jne     e8no1                   ; go on to next
2951         or      ecx,ecx
2952         jnz     e8go2
2953         cmp     eax,#0x100000   ; compare to 1Mb
2954         ja      e8go2
2955         add     eax,memmap+8    ; get final address
2956         adc     ecx,memmap+12   ;
2957         shrd    eax,ecx,#10     ; convert to 1k blocks (legacy)
2958         cmp     eax,#4*1024     ; compare to 4Mb
2959         jb      no_e820
2960         xchg    eax,edx         ; save in edx
2961         jmp     e8go2
2962
2963 e8no1:  shrd    eax,ecx,#10     ; convert to 1k blocks
2964         cmp     eax,#1024       ; compare to 1Mb
2965         jb      e8go2           ; loop if too small
2966         cmp     eax,edx         ; check against HMA
2967         jae     e8go2
2968         xchg    eax,edx         ; compensate for buggy BIOS
2969         jmp     e8go2           ; remember in EDX & loop
2970 #else
2971         cmp     word memmap+16,#1       ; available?
2972         jne     e8go2
2973         mov     eax,memmap+4    ; hi part of start
2974         shrd    memmap,eax,#10  ; convert start to 1k
2975         mov     eax,memmap+12   ; hi part of size
2976         shrd    memmap+8,eax,#10 ; convert to 1k
2977         cmp     dword memmap,#1024      ; below 1M
2978         jb      e8go2           ; below 1M, no interest
2979         cmp     esi,memmap+8    ; check size
2980         ja      e8go2           ; want largest
2981         mov     edx,memmap      ; start (in 1k)
2982         mov     esi,memmap+8    ; size (in 1k)
2983         add     edx,esi         ; HMA in 1k
2984         jmp     e8go2
2985 #endif
2986 e8go5:  or      edx,edx         ; find anything?
2987         jz      no_e820
2988         xchg    eax,edx
2989         jmp     rd_have_hma
2990 no_e820:
2991 ; above failed, try the older E801 block count interface
2992         xor     cx,cx           ; some BIOSs are buggy
2993         xor     dx,dx
2994         mov     ax,#0xe801      ; call
2995         stc
2996         int     0x15
2997         jc      no_e801
2998         or      cx,cx
2999         jz      e801cx
3000         mov     ax,cx
3001 e801cx: or      dx,dx
3002         jz      e801dx
3003         mov     bx,dx
3004 e801dx: 
3005         movzx   ebx,bx
3006         movzx   eax,ax
3007         shl     ebx,#6          ; convert 64k to 1k
3008         mov     ecx,#16*1024
3009         cmp     eax,ebx         ; compare sizes
3010         ja      e801eax
3011         add     ebx,ecx         ; add in 16M
3012         mov     eax,ebx         ; and use this value
3013         jmp     rd_have_hma
3014 e801eax:
3015         add     eax,#1024       ; add 1M
3016         cmp     eax,ecx         ; is it 16M
3017         jne     rd_have_hma
3018         add     eax,ebx         ; add in ebx
3019         jmp     rd_have_hma
3020 #endif  /* ifndef LCF_INITRDLOW */
3021 no_e801:
3022 ; above two methods failed, try the old 0x88 function
3023         mov     ah,#0x88        ; get count of extended memory blocks
3024         int     0x15
3025         movzx   eax,ax          ; extend to dword
3026         add     eax,#1024       ; add in base 1M
3027 ;
3028 rd_have_hma:    ; have the HMA / 1k in EAX
3029 #if DEBUG_NEW
3030         push    eax
3031         shl     eax,10          ; convert to address
3032         push    eax
3033         call    crlf
3034         call    dout            ; pops its argument
3035         mov     bx,#msg_hma
3036         call    say
3037         pop     eax
3038 #endif
3039         mov     ebx,#15*1024    ; 15Mb
3040         cmp     eax,ebx         ; compare to 15M
3041         jbe     rd_use_eax      ; use lower value
3042         BEG_FS
3043         SEG_FS
3044         test    byte ptr par1_prompt+SSDIFF,#FLAG_LARGEMEM
3045         END_FS
3046         jnz     large_okay
3047         xchg    eax,ebx         ; limit to 15Mb
3048 large_okay:
3049         mov     ebx,#HIGHMEM_MAX/1024
3050 #ifdef NEW3_HDR_VERSION
3051         push    ds
3052         mov     ds,[initseg]    ; load the original boot sector
3053         cmp     word ptr [CL_HDRS_VERSION],#NEW3_HDR_VERSION
3054         jb      not203
3055         mov     ebx,[CL_RAMDISK_MAX]
3056 #if DEBUG_NEW
3057         pop     cx
3058         push    cx
3059         mov     ds,cx
3060         pushad
3061         push    ebx
3062         mov     bx,#hdr3
3063         call    say
3064         call    dout
3065         call    crlf
3066         popad
3067 #endif
3068         dec     ebx
3069         shr     ebx,#10         ; divide by 1024
3070         inc     ebx
3071 not203:
3072         pop     ds
3073 #endif  /* ifdef NEW3_HDR_VERSION */
3074         cmp     eax,ebx
3075         jb      rd_use_eax
3076 ;;;rd_use_smaller:
3077         xchg    eax,ebx         ; must use the smaller
3078 rd_use_eax:
3079         pop     bx              ; get size in pages
3080         shr     eax,2           ; convert to pages
3081         movzx   ebx,bx          ; zero high part of size
3082         sub     eax,ebx         ; start address of ramdisk to EAX
3083 #if DEBUG_INITRD
3084         cmp     dword ptr [hma],#0x180000/1024 ; 1.5Mb
3085         jb      drd_use_eax
3086         cmp     dword ptr [hma],#0xF00000/1024  ; 15Mb
3087         jae     drd_use_eax
3088         mov     eax,[hma]       ; HMA is initrd start
3089         shr     eax,2
3090 drd_use_eax:
3091 #endif
3092 #if 0
3093         cmp     eax,#256        ; we probably need more than 1M for the
3094         ja      rd_okay         ;   kernel to be useful ...
3095         mov     bx,#msg_rd      ; complain
3096 ;;;     call    say             ; is at zz
3097         br      zz              ; and halt 
3098 #else
3099         cmp     eax,#4*256      ; Ramdisk loaded below 4Mb
3100         jae     rd_okay         ;   kernel to be useful ...
3101         mov     bx,#msg_rd4M    ; complain
3102         call    say             ; is at zz
3103 #endif
3104 rd_okay:
3105         shl     eax,4           ; shift (12-8) -> 4
3106         mov     [rdbeg+1],ax    ; set up beginning address
3107         mov     [gdt+0x1b],ax   ; set the GDT for the moves
3108         shr     eax,16          ; get hi-byte of address
3109         mov     [rdbeg+3],al    ; set rest of address
3110         mov     [gdt+0x1f],al   ; and in the GDT, too
3111         ret
3112 /* endif / ifdef HIGHMEM_MAX */
3113
3114
3115 /* enter with SI pointing to DESCRIPTOR 
3116         DS = CS
3117         ES unknown
3118         SI - points at the descriptor
3119 */
3120 load_initrd:
3121         push    [map]
3122         push    [moff]
3123         mov     word ptr [map],#MAP2
3124         push    ds
3125         pop     es
3126         mov     ax,(si+id_flags)        ; get FLAG_TOOBIG, if any
3127 #if FLAG_LARGEMEM!=FLAG_TOOBIG
3128 # error "FLAG_LARGEMEM and FLAG_TOOBIG must be equal"
3129 #endif
3130         and     al,#FLAG_TOOBIG         ; separate flag
3131         BEG_FS
3132         SEG_FS
3133         or      byte ptr par1_prompt+SSDIFF, al ; set FLAG_LARGEMEM
3134         END_FS
3135         add     si,#id_rd_size  ; point at ramdisk size long
3136 ! take care of the RAM disk first
3137         xor     eax,eax
3138         mov     (rdbeg),eax     ; clear address
3139         lodsd
3140         mov     (rdszl),eax     ; set rdszl+rdszh
3141         add     eax,#4095       ; round up &
3142         shr     eax,#12         ; convert to pages
3143         xchg    bx,ax           ; copy to BX
3144         lodsw                   ; address of the first map sector
3145         xchg    cx,ax
3146         lodsw
3147         xchg    dx,ax
3148         lodsb                   
3149         or      bx,bx           ; no RAM disk ?
3150         jz      noramd          ; yes -> skip it 2
3151
3152         push    si              ; save SI, ES, and BX (RD size)
3153         push    es
3154         push    bx
3155         mov     bx,[map]                ; load the first map sector
3156         call    sread
3157         mov     moff,#0
3158 #ifdef DEBUG
3159         mov bx,#stepa
3160         call say
3161 #endif
3162 /* ifdef HIGHMEM_MAX */
3163         pop     bx
3164         call    rd_setup
3165 /* endif */
3166         cmp     dword ptr (rdbeg),#0
3167         je      nordpt          ; no -> no need to patch header for that
3168 ; setrdp:
3169 #if DEBUG_NEW
3170         push    dword (rdbeg)   ; print RAM disk address
3171         mov     bx,#msg_rd2
3172         call    say
3173         call    dout
3174         call    crlf
3175 #endif
3176         mov     es,[setupseg]   ; load the setup codes
3177         mov     eax,(rdbeg)     ; get RAM disk start address
3178         seg     es
3179         mov     (24),eax        ; store in header
3180         mov     eax,rdszl
3181         seg     es
3182         mov     (28),eax        ; set RAM disk size
3183 nordpt: 
3184         push    #0              ; ES=0 is our secret code to load via GDT
3185         pop     es
3186         mov     bx,#gdt
3187         call    lfile           ; load it
3188 #if 1
3189         mov     al,#0x20        ; print a space
3190         call    display
3191 #endif
3192         pop     es              ; restore ES and SI
3193         pop     si
3194 noramd:
3195         pop     [moff]
3196         pop     [map]
3197         ret
3198
3199 #ifndef LCF_NOSERIAL
3200 serLI:  .byte   13,10,0x4c,0x49         ; cr,lf,"LI"
3201
3202 BAUD_BASE = 115200                      ; divisor == 1
3203 divisor:
3204         .byte   BAUD_BASE / 19200       ; must be same as bsect.c table
3205         .byte   BAUD_BASE / 38400
3206         .byte   BAUD_BASE / 57600
3207         .byte   BAUD_BASE / 115200
3208         .byte   BAUD_BASE / 2400
3209         .byte   BAUD_BASE / 2400
3210         .byte   BAUD_BASE / 2400
3211         .byte   BAUD_BASE / 2400
3212
3213 ; serial_setup -- do the setup for the serial line communications
3214 ;
3215 ;       No registers are saved
3216 ;
3217 serial_setup:
3218 ;;      BEG_FS
3219 ;;      SEG_FS
3220         mov     dx,par2_port    ; use a COM port ?
3221                         ; watch out, loads par2_ser_param
3222 ;;      END_FS
3223         dec     dl
3224         js      nocom           ; no -> go on
3225         xor     ax,ax           ; initialize the serial port
3226         xchg    al,dh
3227
3228         push    ax
3229         push    dx
3230
3231 ;;;     or      al,#0x06        ; stop bits = 2, nbits = 7 or 8
3232                                 ; this OR is not needed yet (21.7)
3233         int     0x14            ; Communications Port INIT
3234
3235         push    #0x40
3236         pop     ds
3237
3238         pop     bx              ; was DX
3239
3240         shl     bx,#1
3241         mov     dx,(bx)         ; get the port address from the BIOS
3242
3243         seg     cs              ; keep it
3244         mov     slbase,dx
3245
3246         pop     bx              ; special baud rate test -- was AX
3247
3248         test    bl,#0x04                ; stop bits == 2?
3249         cli                     ; do not disturb any code below
3250         jz      stdbps          ; standard BPS
3251
3252         shr     bx,#5           ; index divisor array
3253         seg     cs
3254         mov     bl,divisor(bx)
3255
3256 spcbps:                         ; CLI: do not disturb ...
3257         push    dx              ; save base address
3258         add     dx,#3           ; enable divisor latch access
3259         in      al,dx
3260         or      al,#0x80
3261         out     dx,al
3262         pop     dx              ; set new divisor
3263         push    dx
3264         xchg    ax,bx
3265         out     dx,al
3266         inc     dx
3267         mov     al,ah
3268         out     dx,al
3269         inc     dx              ; disable divisor latch access
3270         inc     dx
3271         xchg    ax,bx
3272         and     al,#0x7f
3273         out     dx,al
3274         pop     dx              ; restore base address
3275
3276 stdbps:                         ; CLI: redundant if fell in from above
3277         push    dx
3278         add     dx,#4           ; address Modem Control Reg.
3279 #if 0
3280         in      al,dx
3281         or      al,#3           ; turn on DTR and RTS
3282 #else
3283         mov     al,#3           ; turn on DTR and RTS
3284 #endif
3285         out     dx,al
3286         pop     dx
3287         sti                     ; done
3288         
3289         mov     cx,#32          ; drain the queue (if any)
3290 drain:  in      al,dx
3291         loop    drain
3292         add     dx,#5           ; clear the status register
3293         in      al,dx
3294
3295     ; send "\r\nLI" to the serial port
3296
3297         mov     si,#serLI
3298         mov     cx,#4
3299 ser1:   seg     cs
3300         lodsb
3301         call    serdisp
3302         loop    ser1
3303
3304 nocom:
3305         ret
3306
3307 #endif          /* LCF_NOSERIAL */
3308
3309
3310
3311 #ifdef SHS_PASSWORDS
3312 #include "shs3.S"
3313 #endif
3314 #include "read.S"
3315 #include "volume.S"
3316 #define SECOND_STAGE_LOADER
3317 #include "mapper.S"
3318 #undef SECOND_STAGE_LOADER
3319 #ifdef LCF_BDATA
3320 #include "bdata.h"
3321 #include "biosdata.S"
3322 #endif
3323 #if defined(MENU) || defined(BITMAP) || DEBUG_NEW
3324 #include "strlen.S"
3325 #endif
3326 #ifdef MENU
3327 #include "graph.S"
3328 #include "menu.S"
3329 #include "crt.S"
3330 #endif
3331 #ifdef BITMAP
3332 #include "bitmap.S"
3333 #include "vesainfo.h"
3334 #include "display4.S"
3335 #endif
3336
3337 ! Put tokens into keyboard buffer
3338
3339 putkbd: add     si,#4           ; skip over "kbd="
3340         push    es
3341         xor     ax,ax           ; set ES to zero
3342         mov     es,ax
3343 pknext: lodsb                   ; get next byte
3344         or      al,al           ; NUL ?
3345         jz      pkdone          ; yes -> done
3346         cmp     al,#32          ; blank ?
3347         jne     pkrd            ; no -> read scan code
3348 pkdone: dec     si              ; return last character
3349         pop     es              ; done
3350         ret
3351 pkrd:   xor     cx,cx           ; clear accumulator
3352 pkrdlp: cmp     al,#97          ; lower case character ?
3353         jb      pknol           ; no -> go on
3354         sub     al,#32          ; make upper case
3355 pknol:  sub     al,#48          ; normalize
3356         cmp     al,#10          ; >"9" ?
3357         jb      pkok            ; no -> okay
3358         cmp     al,#17          ; <"A" ?
3359         jb      pksyn           ; yes -> syntax error
3360         sub     al,#7           ; adjust
3361         cmp     al,#16          ; >"F" ?
3362         jae     pksyn           ; yes -> syntax error
3363 pkok:   shl     cx,1            ; shift CX
3364         jc      pksyn           ; carry means trouble
3365         shl     cx,1
3366         jc      pksyn
3367         shl     cx,1
3368         jc      pksyn
3369         shl     cx,1
3370         jc      pksyn
3371         add     cl,al           ; put in lowest nibble
3372         lodsb                   ; get next byte
3373         or      al,al           ; NUL ?
3374         jz      pkend           ; yes -> at end
3375         cmp     al,#32          ; space ?
3376         je      pkend           ; yes -> at end
3377         cmp     al,#44          ; comma ?
3378         je      pkmore          ; yes -> end of token
3379         jmp     pkrdlp          ; token continues
3380 pksyn:  mov     bx,#msg_pks     ; complain
3381         call    say
3382 pkfls:  lodsb                   ; flush to end of option
3383         or      al,al
3384         jz      pkdone
3385         cmp     al,#32
3386         je      pkdone
3387         jmp     pkfls
3388 pkend:  call    pkput           ; store token
3389         jmp     pkdone          ; ... and return
3390 pkmore: call    pkput           ; store token
3391         jmp     pknext          ; handle next token
3392 pkput:  seg     es              ; get buffer pointer
3393         mov     bx,[KBEND]
3394         mov     dx,bx
3395         add     dx,#2           ; increment it
3396         cmp     dx,#KBHIGH      ; (wrap around end)
3397         jb      pknadj
3398         mov     dx,#KBLOW
3399 pknadj: seg     es              ; buffer full ?
3400         cmp     dx,[KBBEG]
3401         je      pkfull          ; yes -> error
3402         seg     es              ; store scan code
3403         mov     (bx+0x400),cx
3404         seg     es              ; store new pointer
3405         mov     [KBEND],dx
3406         ret                     ; done
3407 pkfull: mov     bx,#msg_pkf     ; complain
3408         call    say
3409         pop     ax              ; discard return address
3410         jmp     pkfls           ; abort
3411
3412 ! Set VGA mode
3413
3414 setvga: add     si,#4           ; skip over "vga="
3415         push    si              ; save SI
3416         mov     bx,#vgatab      ; scan VGA table
3417 svgatb: pop     si              ; get pointer to option value
3418         push    si
3419         mov     cx,(bx)         ; get VGA code
3420         or      cx,cx           ; at end ?
3421         jz      vganum          ; yes -> must be numeric
3422         inc     bx              ; compare the strings
3423         inc     bx
3424 vgacmp: lodsb
3425         call    upcase          ; (case-insensitive)
3426         mov     ah,(bx)
3427         inc     bx
3428         or      ah,ah           ; at end ?
3429         jnz     vgamore         ; no -> go on
3430         or      al,al           ; at end of line ?
3431         jz      vgafnd          ; yes -> found it
3432         cmp     al,#32          ; space ?
3433         je      vgafnd          ; yes -> found it
3434         jmp     svgatb          ; try next entry otherwise
3435 vgamore:cmp     al,ah
3436         je      vgacmp          ; equal -> next character
3437 vgaskp: mov     al,(bx)         ; skip to end of reference string
3438         inc     bx
3439         or      al,al
3440         jnz     vgaskp
3441         jmp     svgatb          ; try next entry
3442 vgafnd: pop     ax              ; drop SI
3443
3444 vgaput: dec     si              ; read last character again
3445 vgaput1: mov    vgaovr,cx       ; set VGA mode
3446         clc                     ; okay, done
3447         ret
3448
3449 vganum: pop     si              ; get SI
3450 #if 1
3451         call    strtoul
3452         jc      vgaerr
3453         mov     cx,ax
3454         or      dx,dx
3455         jnz     vgaerr
3456         jmp     vgaput1
3457 #else
3458         xor     cx,cx
3459         mov     ah,cl
3460         test    byte ptr (si),#0xff ; no value ?
3461         jz      vgaerr          ; yes -> error
3462 vgadig: lodsb                   ; get the next character
3463         or      al,al           ; at end ?
3464         jz      vgaput          ; yes -> done
3465         cmp     al,#32
3466         je      vgaput
3467         cmp     al,#48          ; is it a digit ?  (0x30=48="0")
3468         jb      vgaerr          ; no -> error
3469         cmp     al,#57          ; 57=0x39="9"
3470         ja      vgaerr
3471         sub     al,#48          ; cx = cx*10+al-'0'
3472         imul    cx,#10
3473         add     cx,ax
3474         jnc     vgadig          ; next one
3475 #endif
3476
3477 vgaerr: mov     bx,#msg_v       ; display an error message
3478         call    say
3479 /* ifdef HIGHMEM_MAX */
3480         xor     eax,eax
3481         mov     dword ptr [hma],eax
3482 /* endif */
3483         stc                     ; return an error
3484         ret
3485
3486 vgatab:
3487 #ifdef NORMAL_VGA
3488         .word   ASK_VGA
3489         .ascii  "ASK"
3490         .byte   0
3491         .word   EXTENDED_VGA
3492         .ascii  "EXTENDED"
3493         .byte   0
3494         .word   EXTENDED_VGA
3495         .ascii  "EXT"
3496         .byte   0
3497         .word   NORMAL_VGA
3498         .ascii  "NORMAL"
3499         .byte   0
3500 #endif
3501         .word   0
3502
3503
3504 ! get numeric string suffixed with "KkMmGg"
3505 ! updates SI
3506
3507 get_K:
3508         push    cx              ; save CX
3509
3510         call    strtoull        ; get number in DX:AX
3511         jc      gmthis2         ; signal conversion error
3512
3513         mov     bl,(si)         ; get next character
3514         or      bl,#0x20        ; convert to lower case
3515         cmp     bl,#0x6b        ; 'K' or 'k' ?
3516         je      gmthis          ; yes -> do not change
3517 #if 1
3518         mov     cx,#20          ; divide or multiply by 2^20
3519         cmp     bl,#0x67        ; 'G' or 'g' ?
3520         je      gmmul
3521 #endif
3522         mov     cx,#10          ; divide or multiply by 2^10
3523         cmp     bl,#0x6d        ; 'M' or 'm' ?
3524         je      gmmul
3525
3526 ! no Suffix
3527         dec     si              ; will increment later
3528         
3529 gmdivl:
3530         shr     eax,cl          ; shift by CL
3531         jmp     gmthis          ; done
3532 gmmul:
3533 gmmull:
3534         shl     eax,1           ; shift by 1 each time
3535         jc      gmvbig          ; very big if overflow
3536         loop    gmmull          ; ten times
3537
3538 ! exit with no error
3539
3540 gmthis:
3541         inc     si
3542         clc                     ; signal no error
3543 gmthis2:
3544         mov     bl,(si)         ; next character to BL
3545 #if 0
3546         jc      gmdebug1
3547         pushad
3548         push    eax
3549         call    dout
3550         mov     bx,#msg_gk
3551         call    say
3552         popad
3553 gmdebug1:
3554 #endif
3555         pop     cx              ; restore register
3556         ret
3557
3558 gmvbig:
3559         mov     eax,#HIGHMEM_MAX/1024
3560         jmp     gmthis
3561
3562
3563 ! Set memory limit
3564
3565 getmem:
3566         push    si              ; save SI for copying
3567         add     si,#4           ; advance to number?
3568         call    get_K
3569         jc      gmcopy          ; error, just copy it
3570
3571         cmp     bl,#0x40        ; is it '@'
3572         jne     gm22
3573 ! <size>@<start> format (2.4 kernels)
3574         push    eax             ; save size
3575         inc     si              ; skip '@'
3576         call    get_K
3577         pop     edx             ; restore size
3578         jc      memerr
3579         cmp     eax,#1024       ; start : 1meg
3580         ja      gmcopy          ; just copy if above
3581         add     eax,edx         ; EAX = hma/1024
3582         cmp     eax,#2048       ; high : 2meg
3583         jbe     gmcopy
3584 gm22:
3585         or      bl,#0x20
3586         cmp     bl,#0x20        ; NUL or SPACE
3587 #if 0
3588         jne     memerr
3589 #else
3590         jne     gmcopy          ; allow <size>#<start> and <size>$<start>
3591 #endif
3592         cmp     dword ptr [hma],#0      ; set already?
3593         jne     gmnocopy
3594         mov     dword ptr [hma],eax     ; set it        
3595 gmcopy: pop     si
3596 gmret:  ret
3597 gmnocopy:  pop  bx
3598         ret
3599
3600
3601 memerr:
3602         mov     bx,#msg_me      ; numeric conversion error
3603         call    say
3604         br      restrt
3605
3606 strtoull:                       ; numeric conversion to EAX
3607         call    strtoul
3608         push    dx
3609         push    ax
3610         pop     eax
3611         ret
3612
3613 strtoul:          /* string to unsigned long in DX:AX */
3614         xor     ax,ax
3615         xor     dx,dx
3616         mov     cx,#10          ; default radix is decimal
3617         cmp     byte ptr (si),#0x39
3618         ja      s2lbad          ; error if > '9'
3619         cmp     byte ptr (si),#0x30        ; == '0'?
3620         jb      s2lbad          ; error if < '0'
3621         jne     s2lnext
3622         inc     si
3623         dec     cx
3624         dec     cx              ; assume octal : CX = 8
3625         
3626         cmp     byte ptr (si),#0x58        ; == 'X'?
3627         je      s2lhex
3628         cmp     byte ptr (si),#0x78        ; == 'x'?
3629         jne     s2lnext
3630 s2lhex: add     cx,cx           ; it is hexadecimal
3631         inc     si
3632 s2lnext:
3633         xor     bx,bx
3634         mov     bl,(si)         ; get next character
3635
3636         or      bl,#0x20        ; convert to lower case
3637         sub     bl,#0x30        ; - '0'
3638         jb      s2ldone
3639         cmp     bl,cl           ; compare to radix
3640         jb      s2lmul
3641         add     bl,#0x30-0x61+10
3642         cmp     bl,cl           ; compare to radix
3643         jnb     s2ldone
3644 s2lmul:
3645         push    dx              ; save high order
3646         mul     cx              ; multiply by radix
3647         add     ax,bx
3648         adc     dx,#0           ; carry possible only in radix 10
3649         pop     bx
3650         push    dx
3651         xchg    ax,bx
3652         mul     cx
3653         or      dx,dx
3654         jnz     s2lbad
3655         pop     dx
3656         add     dx,ax
3657         jc      s2lbad
3658         xchg    ax,bx
3659         inc     si
3660         jmp     s2lnext
3661
3662 s2lbad: 
3663         stc
3664         ret
3665         
3666 s2ldone:
3667         clc 
3668         ret
3669
3670 /* new 22.7 */
3671 ; find_image
3672 ;       if there is something on the command line
3673 ;       return the image number it selects
3674 ;
3675 ;       enter with:
3676 ;               nothing
3677 ;       exit with:
3678 ;               If nothing selected:
3679 ;                   Carry Clear
3680 ;                   AX==0
3681 ;               If an image is selected:
3682 ;               (fuzzy selection or exact selection)
3683 ;                   Carry SET
3684 ;                   AX==#image
3685 ;                   BX==pointer to descriptor
3686 ;                   
3687 ;
3688 ;       side effect:
3689 ;               The selected image is hi-lited if the menu is displayed
3690 ;
3691 find_image:
3692         push    cx
3693         push    si
3694         push    di
3695         
3696         mov     cx,#IMAGES      ; test all names
3697         mov     si,#DESCR0
3698         xor     bx,bx           ; clear BX
3699         push    si
3700
3701 fi_nextn:
3702         mov     di,#cmdline
3703         test    byte ptr (si),#0xFF     ; null descriptor at end
3704         jz      fi_nomore
3705
3706 fi_nextc:
3707         mov     al,(si)         ; get next character in descr
3708         inc     si
3709 #ifdef LCF_IGNORECASE
3710         call    upcase
3711 #endif
3712         mov     ah,al
3713         mov     al,(di)         ; get next char in cmdline
3714         inc     di
3715 #ifdef LCF_IGNORECASE
3716         call    upcase
3717 #endif
3718         or      al,al           ; NUL in command line
3719         je      fi_pmat
3720         cmp     al,#32          ; SPACE in command line
3721         jne     fi_cmp
3722
3723 ; have partial match, set BX conditionally
3724 fi_pmat:
3725         or      ah,ah           ; NUL in descriptor name
3726         jz      fi_found        ; EXACT match found
3727
3728         test    byte ptr par2_flag2,#FLAG2_UNATTENDED   ; (22.7)
3729         jnz     fi_skipn        ; no partial match if unattended
3730
3731         or      bx,bx
3732         jnz     fi_skipn        ; already set
3733         pop     bx
3734         push    bx
3735         jmp     fi_skipn        ; go to next
3736
3737 fi_cmp:
3738         cmp     al,ah           ; character equal ?
3739         je      fi_nextc        ; compare next character
3740
3741 ; advance to next descriptor
3742 fi_skipn:
3743         pop     si
3744         add     si,#id_size     ; test next name
3745         push    si
3746         loop    fi_nextn
3747
3748 fi_nomore:
3749         pop     si
3750         or      bx,bx           ; fuzzy match?
3751         jnz     fi_fuzzy
3752
3753 #if defined(MENU) || defined(BITMAP)
3754         mov     ax,[dimage]
3755         call    lowlite         ; no match, nothing hi-lited
3756 ;;;     mov     word [dimage],#0
3757 #endif
3758         xor     ax,ax           ; clears the carry
3759 fi_exit:
3760         pop     di
3761         pop     si
3762         pop     cx
3763         ret
3764         
3765 fi_found:
3766         pop     bx              ; BX is matched descriptor
3767 fi_fuzzy:
3768         mov     ax,bx
3769         sub     ax,#DESCR0
3770         mov     cl,#id_size
3771         div     cl
3772         cbw
3773 #if defined(MENU) || defined(BITMAP)
3774         mov     di,[dimage]
3775         mov     [dimage],ax
3776         cmp     byte [abs_cx+1],#0      ; see if menu is displayed
3777         je      fi_nochange
3778         cmp     ax,di
3779         je      fi_nochange2
3780         xchg    ax,di
3781         call    lowlite
3782         xchg    ax,di
3783 fi_nochange2:
3784         call    hilite
3785 fi_nochange:
3786 #endif
3787         stc
3788         jmp     fi_exit
3789 /* end new 22.7 */
3790
3791 #if DEBUG_NEW
3792 ; check that nobody has changed the FS register
3793 fs_check:
3794         push    ax
3795         mov     ax,fs
3796         seg cs
3797         cmp     ax,[firstseg]
3798         je      fs_check_okay
3799 ; oops, somebody changed it !!!
3800         pop     ax      ; restore
3801         pop     ax      ; get return
3802         push    cs
3803         pop     ds
3804         sub     ax,#3   ; length of call
3805         call    wout
3806         mov     bx,#msg_fs_changed
3807         br      zz
3808 fs_check_okay:
3809 #if CHECK_FS_VERBOSE
3810         pusha
3811         mov     bp,sp
3812         mov     ax,16+2(bp)
3813         sub     ax,#3
3814         call    wout
3815         mov     bx,#msg_fs_okay
3816         push    ds
3817         push    cs
3818         pop     ds
3819         call    say
3820         pop     ds
3821         popa
3822 #endif
3823 fs_check_ret:
3824         pop     ax
3825         ret
3826 msg_fs_changed:
3827         .ascii  " <- loc where FS is clobbered\n"
3828         .byte   0
3829 #if CHECK_FS_VERBOSE
3830 msg_fs_okay:
3831         .ascii  " <- FS okay\n"
3832         .byte   0
3833 #endif
3834 #endif
3835
3836 ! Some messages
3837
3838 msg_p:  .ascii  "boot: "
3839         .byte   0
3840
3841 msg_l:  .ascii  "Loading "
3842         .byte   0
3843
3844 msg_bc: .ascii  "BIOS data check "
3845         .byte   0
3846
3847 msg_s:  .ascii  "successful\n"
3848         .byte   0
3849
3850 msg_by: .ascii  "bypassed\n"
3851         .byte   0
3852
3853 msg_re: .byte   10
3854         .ascii  "Error 0x"
3855         .byte   0
3856
3857 msg_nf: .ascii  "No such image. [Tab] shows a list."
3858         .byte   10,0
3859
3860 msg_time:
3861         .ascii  "O - Timestamp mismatch\n"
3862         .byte   0
3863
3864 msg_chkerr:
3865         .ascii  "O - Descriptor checksum error\n"
3866         .byte   0
3867
3868 msg_chkkey:
3869         .ascii  "O - Keytable read/checksum error\n"
3870         .byte   0
3871
3872 msg_confl:
3873         .ascii  "Kernel and Initrd memory conflict\n"
3874         .byte   0
3875
3876 msg_sigerr:
3877         .ascii  "O - Signature not found\n"
3878         .byte   0
3879
3880 msg_me: .byte   10
3881         .ascii  "vga/mem=  requires a numeric value"
3882         .byte   10,0
3883
3884 msg_wrerr:      .ascii  "\nMap file write; BIOS error code = 0x"
3885         .byte   0
3886
3887 msg_wrerr3:     .ascii  "\nMap file: WRITE PROTECT\n"
3888         .byte   0
3889
3890 #ifdef MEMORY_CHECK
3891 msg_mem: .ascii "EBDA is big; kernel setup stack overlaps LILO second stage"
3892         .byte   10,0
3893 #endif
3894
3895 #ifdef LCF_VIRTUAL
3896 msg_vmwarn:
3897         .ascii  "WARNING:  Booting in Virtual environment\n"
3898         .ascii  "Do you wish to continue? [y/n] "
3899         .byte   0
3900 #endif
3901
3902 #if DEBUG_NEW
3903 sdx:    .ascii  " DX="
3904         .byte   0
3905
3906 msg_pl: .ascii  "\nParameter line = "
3907         .byte   0
3908 #ifdef LCF_NOKEYBOARD
3909 msg_kbtest:
3910         .ascii  "**PC/AT Keyboard test**\n"
3911         .byte   0
3912 #endif
3913
3914 #if defined(LCF_VIRTUAL) || defined(LCF_NOKEYBOARD)
3915 msg_real:
3916         .ascii  "Performing REAL MODE boot\n"
3917         .byte   0
3918
3919 #ifdef LCF_VIRTUAL
3920 msg_virtual:
3921         .ascii  "Performing VIRTUAL MODE boot\n"
3922         .byte   0
3923 #endif
3924 #ifdef LCF_NOKEYBOARD
3925 msg_no_keyboard:
3926         .ascii  "Performing NO KEYBOARD DEFAULT boot\n"
3927         .byte   0
3928 #endif
3929 #endif
3930
3931 msg_where:
3932         .ascii  "\nINIT SETUP CODE SS:SP  EX_OFF_DX 2ndDX\n"
3933         .byte   0
3934
3935 msg_low: .ascii " low"
3936         .byte   0
3937
3938 msg_high:  .ascii " high"
3939         .byte   0
3940
3941 hdr1:   .ascii  "\nHeader 0x"
3942         .byte   0
3943
3944 hdr2:   .ascii  " cmdline at "
3945         .byte   0
3946
3947 hdr4:   .ascii  "   length = 0x"
3948         .byte   0
3949
3950 hdr3:   .ascii  "\nRamdisk_max "
3951         .byte   0
3952
3953 nohdrs: .ascii  "\nNo cmdline passed"
3954         .byte   0
3955
3956 msg_rd2: .byte  10
3957         .ascii  "RAM disk loaded at: "
3958         .byte   0
3959
3960 msg_hma: .ascii " is the HMA\n"
3961         .byte   0
3962
3963 msg_gk: .ascii  " returned by 'get_K'\n"
3964         .byte   0
3965
3966 #endif
3967
3968 msg_int:.byte   10
3969         .ascii  "*Interrupted*"
3970         .byte   10,0
3971
3972 msg_eof:.byte   10
3973         .ascii  "Unexpected EOF"
3974         .byte   10,0
3975
3976 msg_pw: .ascii  "Password: "
3977         .byte   0
3978
3979 msg_pf: .ascii  "Sorry."
3980         .byte   10,0
3981
3982 msg_v:  .byte   10
3983         .ascii  "Valid vga values are ASK, NORMAL, EXTENDED or a "
3984         .ascii  "decimal number."
3985         .byte   10,0
3986
3987 msg_pks:.byte   10
3988         .ascii  "Invalid hexadecimal number. - Ignoring remaining items."
3989         .byte   10,0
3990
3991 msg_pkf:.byte   10
3992         .ascii  "Keyboard buffer is full. - Ignoring remaining items."
3993         .byte   10,0
3994
3995 msg_bm: .byte   10
3996         .ascii  "Block move error 0x"
3997         .byte   0
3998
3999 #if 0
4000 msg_rd: .byte   10
4001         .ascii  "Not enough memory for RAM disk"
4002         .byte   10,0
4003 #else
4004 msg_rd4M: .byte 10
4005         .ascii  "Initial ramdisk loads below 4Mb; "
4006         .ascii  "kernel overwrite is possible."
4007         .byte   10,0
4008 #endif
4009
4010 ospc:   .ascii  "O"
4011 #ifdef LCF_BEEP
4012         .byte   7
4013 #endif
4014 #ifdef LCF_VERSION
4015         .ascii  " "     
4016         .ascii  SA(VERSION_MAJOR)
4017         .ascii  "."
4018         .ascii  SA(VERSION_MINOR)
4019         .ascii  VERSION_EDIT
4020 #endif
4021         .byte   32,0
4022
4023 bs:     .byte   8,32,8,0
4024
4025 #ifdef DEBUG
4026 stepa:  .ascii  " RAM disk,"
4027         .byte   0
4028 step0:  .ascii  " map page,"
4029         .byte   0
4030 step0b: .ascii  " fallback,"
4031         .byte   0
4032 step1:  .ascii  " options,"
4033         .byte   0
4034 step1b: .ascii  " fallback,"
4035         .byte   0
4036 step2:  .ascii  " boot,"
4037         .byte   0
4038 step3:  .ascii  " setup,"
4039         .byte   0
4040 step4:  .ascii  " system "
4041         .byte   0
4042
4043 sax:    .ascii  "AX="
4044         .byte   0
4045 sbx:    .ascii  " BX="
4046         .byte   0
4047 scx:    .ascii  " CX="
4048         .byte   0
4049 ses:    .ascii  " ES="
4050         .byte   0
4051 sdone:  .byte   10
4052         .byte   0
4053
4054 mov_ar: .ascii  " -> "
4055         .byte   0
4056 mov_sz: .ascii  ", words "
4057         .byte   0
4058 #endif
4059
4060         .even
4061
4062 init_dx:        .word   0
4063
4064 #if defined(MENU) || defined(BITMAP)
4065 suppress:.word  0               ; suppress console output (MUST be word)
4066 #endif
4067 hinib:  .byte   0               ; hi-nibble of address
4068 tempal: .byte   0
4069 moff:   .word   0               ; map offset
4070 map:    .word   MAP             ; map to use
4071
4072 cntdown:.word   0               ; count-down
4073 timeout:.byte   0               ; timed out
4074
4075 dolock: .byte   0
4076
4077 int1c_l:.word   0               ; old timer interrupt
4078 int1c_h:.word   0
4079
4080 old_del:.word   0               ; delay before booting
4081
4082 nodfl:  .word   0               ; action if no defaults are present
4083
4084 #ifndef LCF_NOSERIAL
4085 slbase: .word   0               ; serial port base (or 0 if unused)
4086 break:  .byte   0               ; break received flag
4087 #endif
4088
4089 usrinpm:.byte   UI_MAGIC
4090
4091 cmdbeg: .word   0
4092 options:.word   0
4093
4094 rdbeg:  .word   0,0             ; RAM dist begin address (dword)
4095
4096 rdszl:  .word   0               ; RAM disk size
4097 rdszh:  .word   0
4098
4099 vgaovr: .word   0               ; VGA mode overwrite
4100
4101 /* ifdef HIGHMEM_MAX */
4102 hma:    .word   0,0             ; Highest Memory Address
4103 memmap: .word   0,0,0,0,0,0,0,0,0,0
4104 /* endif */
4105 dskprm: .word   0,0,0,0,0,0
4106
4107         .even                   ; control alignment from here down
4108 acmdbeg:.ascii  "auto "
4109 mcmdbeg:.ascii  "BOOT_IMAGE"
4110 prechr: .byte   32              ; space: guard double blank supression
4111                                 ; equal sign: variable assignment
4112 cmdline:.byte   0
4113
4114 #ifdef BITMAP
4115 _line   =       cmdline+CL_LENGTH               ; must be 640 bytes long
4116 #endif
4117         .org    *+4
4118 theend:
4119
4120 lkwbuf  =       cmdline+CL_LENGTH+2     ; this is a word
4121 lkcbuf  =       lkwbuf+2
4122 theend2 =       lkcbuf+CL_LENGTH        ; lkcbuf is 256
4123
4124 the_end1        = theend+511
4125 theends =       the_end1/512
4126         .org    theends*512-4
4127         .long   X
4128         .align  512
4129 max_secondary:
4130
4131 #if 0
4132 /* the older version 21 layout */
4133 Map             =       max_secondary + SECTOR_SIZE
4134 Dflcmd          =       Map + SECTOR_SIZE
4135 Map2            =       Dflcmd
4136 Descr           =       Dflcmd + SECTOR_SIZE
4137 Keytable        =       Descr + SECTOR_SIZE*MAX_DESCR_SECS_asm
4138 ParmBSS         =       Keytable + SECTOR_SIZE
4139 #else
4140 /* a possible 22.5.6 layout puts the descriptors last */
4141 Map             =       max_secondary + SECTOR_SIZE
4142 Dflcmd          =       Map + SECTOR_SIZE
4143 Map2            =       Dflcmd
4144 Keytable        =       Dflcmd + SECTOR_SIZE
4145 Descr           =       Keytable + SECTOR_SIZE
4146 ParmBSS         =       Descr + SECTOR_SIZE*MAX_DESCR_SECS_asm
4147 #endif
4148
4149 #if COMMAND_LINE_SIZE > 256
4150 BSSstart        =       ParmBSS
4151 Parmline        =       BSSstart + SECTOR_SIZE
4152 #else
4153 Parmline        =       ParmBSS
4154 BSSstart        =       Parmline + CL_LENGTH
4155 #endif
4156
4157 !************************************
4158 !  BSS data:
4159 !     moved from  volume.S 
4160
4161 #define BSS_DATA
4162         .org    BSSstart
4163 #include "volume.S"
4164 #ifdef SHS_PASSWORDS
4165 #include "shs3.S"
4166 #endif
4167
4168         .align  512
4169 BSSend  =       *
4170 BSSsize         =       BSSend-BSSstart
4171
4172
4173 Dataend         =       Parmline + SECTOR_SIZE
4174
4175         .org    max_secondary
4176
4177
4178
4179 #if 0
4180 DESCR0 = DESCR+2
4181 #else
4182 DESCR0 = DESCR
4183 #endif