Add support for forcing the filetype, and loading a secondary config file.
[profile/ivi/syslinux.git] / ldlinux.asm
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
3 ;
4 ;  ldlinux.asm
5 ;
6 ;  A program to boot Linux kernels off an MS-DOS formatted floppy disk.  This
7 ;  functionality is good to have for installation floppies, where it may
8 ;  be hard to find a functional Linux system to run LILO off.
9 ;
10 ;  This program allows manipulation of the disk to take place entirely
11 ;  from MS-LOSS, and can be especially useful in conjunction with the
12 ;  umsdos filesystem.
13 ;
14 ;   Copyright (C) 1994-2005  H. Peter Anvin
15 ;
16 ;  This program is free software; you can redistribute it and/or modify
17 ;  it under the terms of the GNU General Public License as published by
18 ;  the Free Software Foundation, Inc., 53 Temple Place Ste 330,
19 ;  Boston MA 02111-1307, USA; either version 2 of the License, or
20 ;  (at your option) any later version; incorporated herein by reference.
21 ;
22 ; ****************************************************************************
23
24 %ifndef IS_MDSLINUX
25 %define IS_SYSLINUX 1
26 %endif
27 %include "head.inc"
28
29 ;
30 ; Some semi-configurable constants... change on your own risk.
31 ;
32 my_id           equ syslinux_id
33 FILENAME_MAX_LG2 equ 4                  ; log2(Max filename size Including final null)
34 FILENAME_MAX    equ 11                  ; Max mangled filename size
35 NULLFILE        equ ' '                 ; First char space == null filename
36 NULLOFFSET      equ 0                   ; Position in which to look
37 retry_count     equ 16                  ; How patient are we with the disk?
38 %assign HIGHMEM_SLOP 0                  ; Avoid this much memory near the top
39 LDLINUX_MAGIC   equ 0x3eb202fe          ; A random number to identify ourselves with
40
41 MAX_OPEN_LG2    equ 6                   ; log2(Max number of open files)
42 MAX_OPEN        equ (1 << MAX_OPEN_LG2)
43
44 SECTOR_SHIFT    equ 9
45 SECTOR_SIZE     equ (1 << SECTOR_SHIFT)
46
47 ;
48 ; This is what we need to do when idle
49 ;
50 %macro  RESET_IDLE 0
51         ; Nothing
52 %endmacro
53 %macro  DO_IDLE 0
54         ; Nothing
55 %endmacro
56
57 ;
58 ; The following structure is used for "virtual kernels"; i.e. LILO-style
59 ; option labels.  The options we permit here are `kernel' and `append
60 ; Since there is no room in the bottom 64K for all of these, we
61 ; stick them at vk_seg:0000 and copy them down before we need them.
62 ;
63                 struc vkernel
64 vk_vname:       resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
65 vk_rname:       resb FILENAME_MAX       ; Real name
66 vk_appendlen:   resw 1
67 vk_type:        resb 1                  ; Type of file
68                 alignb 4
69 vk_append:      resb max_cmd_len+1      ; Command line
70                 alignb 4
71 vk_end:         equ $                   ; Should be <= vk_size
72                 endstruc
73
74 ;
75 ; Segment assignments in the bottom 640K
76 ; Stick to the low 512K in case we're using something like M-systems flash
77 ; which load a driver into low RAM (evil!!)
78 ;
79 ; 0000h - main code/data segment (and BIOS segment)
80 ;
81 real_mode_seg   equ 4000h
82 cache_seg       equ 3000h               ; 64K area for metadata cache
83 vk_seg          equ 2000h               ; Virtual kernels
84 xfer_buf_seg    equ 1000h               ; Bounce buffer for I/O to high mem
85 comboot_seg     equ real_mode_seg       ; COMBOOT image loading zone
86
87 ;
88 ; File structure.  This holds the information for each currently open file.
89 ;
90                 struc open_file_t
91 file_sector     resd 1                  ; Sector pointer (0 = structure free)
92 file_left       resd 1                  ; Number of sectors left
93                 endstruc
94
95 %ifndef DEPEND
96 %if (open_file_t_size & (open_file_t_size-1))
97 %error "open_file_t is not a power of 2"
98 %endif
99 %endif
100
101 ; ---------------------------------------------------------------------------
102 ;   BEGIN CODE
103 ; ---------------------------------------------------------------------------
104
105 ;
106 ; Memory below this point is reserved for the BIOS and the MBR
107 ;
108                 section .earlybss
109 trackbufsize    equ 8192
110 trackbuf        resb trackbufsize       ; Track buffer goes here
111 getcbuf         resb trackbufsize
112                 ; ends at 4800h
113
114                 section .bss
115                 alignb 8
116
117                 ; Expanded superblock
118 SuperInfo       equ $
119                 resq 16                 ; The first 16 bytes expanded 8 times
120 FAT             resd 1                  ; Location of (first) FAT
121 RootDirArea     resd 1                  ; Location of root directory area
122 RootDir         resd 1                  ; Location of root directory proper
123 DataArea        resd 1                  ; Location of data area
124 RootDirSize     resd 1                  ; Root dir size in sectors
125 TotalSectors    resd 1                  ; Total number of sectors
126 EndSector       resd 1                  ; Location of filesystem end
127 ClustSize       resd 1                  ; Bytes/cluster
128 ClustMask       resd 1                  ; Sectors/cluster - 1
129 CopySuper       resb 1                  ; Distinguish .bs versus .bss
130 DriveNumber     resb 1                  ; BIOS drive number
131 ClustShift      resb 1                  ; Shift count for sectors/cluster
132 ClustByteShift  resb 1                  ; Shift count for bytes/cluster
133
134                 alignb open_file_t_size
135 Files           resb MAX_OPEN*open_file_t_size
136
137 ;
138 ; Constants for the xfer_buf_seg
139 ;
140 ; The xfer_buf_seg is also used to store message file buffers.  We
141 ; need two trackbuffers (text and graphics), plus a work buffer
142 ; for the graphics decompressor.
143 ;
144 xbs_textbuf     equ 0                   ; Also hard-coded, do not change
145 xbs_vgabuf      equ trackbufsize
146 xbs_vgatmpbuf   equ 2*trackbufsize
147
148
149                 section .text
150 ;
151 ; Some of the things that have to be saved very early are saved
152 ; "close" to the initial stack pointer offset, in order to
153 ; reduce the code size...
154 ;
155 StackBuf        equ $-44-32             ; Start the stack here (grow down - 4K)
156 PartInfo        equ StackBuf            ; Saved partition table entry
157 FloppyTable     equ PartInfo+16         ; Floppy info table (must follow PartInfo)
158 OrigFDCTabPtr   equ StackBuf-4          ; The high dword on the stack
159
160 ;
161 ; Primary entry point.  Tempting as though it may be, we can't put the
162 ; initial "cli" here; the jmp opcode in the first byte is part of the
163 ; "magic number" (using the term very loosely) for the DOS superblock.
164 ;
165 bootsec         equ $
166                 jmp short start         ; 2 bytes
167                 nop                     ; 1 byte
168 ;
169 ; "Superblock" follows -- it's in the boot sector, so it's already
170 ; loaded and ready for us
171 ;
172 bsOemName       db 'SYSLINUX'           ; The SYS command sets this, so...
173 ;
174 ; These are the fields we actually care about.  We end up expanding them
175 ; all to dword size early in the code, so generate labels for both
176 ; the expanded and unexpanded versions.
177 ;
178 %macro          superb 1
179 bx %+ %1        equ SuperInfo+($-superblock)*8+4
180 bs %+ %1        equ $
181                 zb 1
182 %endmacro
183 %macro          superw 1
184 bx %+ %1        equ SuperInfo+($-superblock)*8
185 bs %+ %1        equ $
186                 zw 1
187 %endmacro
188 %macro          superd 1
189 bx %+ %1        equ $                   ; no expansion for dwords
190 bs %+ %1        equ $
191                 zd 1
192 %endmacro
193 superblock      equ $
194                 superw BytesPerSec
195                 superb SecPerClust
196                 superw ResSectors
197                 superb FATs
198                 superw RootDirEnts
199                 superw Sectors
200                 superb Media
201                 superw FATsecs
202                 superw SecPerTrack
203                 superw Heads
204 superinfo_size  equ ($-superblock)-1    ; How much to expand
205                 superd Hidden
206                 superd HugeSectors
207                 ;
208                 ; This is as far as FAT12/16 and FAT32 are consistent
209                 ;
210                 zb 54                   ; FAT12/16 need 26 more bytes,
211                                         ; FAT32 need 54 more bytes
212 superblock_len  equ $-superblock
213
214 SecPerClust     equ bxSecPerClust
215 ;
216 ; Note we don't check the constraints above now; we did that at install
217 ; time (we hope!)
218 ;
219 start:
220                 cli                     ; No interrupts yet, please
221                 cld                     ; Copy upwards
222 ;
223 ; Set up the stack
224 ;
225                 xor ax,ax
226                 mov ss,ax
227                 mov sp,StackBuf         ; Just below BSS
228                 mov es,ax
229 ;
230 ; DS:SI may contain a partition table entry.  Preserve it for us.
231 ;
232                 mov cx,8                ; Save partition info
233                 mov di,sp
234                 rep movsw
235
236                 mov ds,ax               ; Now we can initialize DS...
237
238 ;
239 ; Now sautee the BIOS floppy info block to that it will support decent-
240 ; size transfers; the floppy block is 11 bytes and is stored in the
241 ; INT 1Eh vector (brilliant waste of resources, eh?)
242 ;
243 ; Of course, if BIOSes had been properly programmed, we wouldn't have
244 ; had to waste precious space with this code.
245 ;
246                 mov bx,fdctab
247                 lfs si,[bx]             ; FS:SI -> original fdctab
248                 push fs                 ; Save on stack in case we need to bail
249                 push si
250
251                 ; Save the old fdctab even if hard disk so the stack layout
252                 ; is the same.  The instructions above do not change the flags
253                 mov [DriveNumber],dl    ; Save drive number in DL
254                 and dl,dl               ; If floppy disk (00-7F), assume no
255                                         ; partition table
256                 js harddisk
257
258 floppy:
259                 mov cl,6                ; 12 bytes (CX == 0)
260                 ; es:di -> FloppyTable already
261                 ; This should be safe to do now, interrupts are off...
262                 mov [bx],di             ; FloppyTable
263                 mov [bx+2],ax           ; Segment 0
264                 fs rep movsw            ; Faster to move words
265                 mov cl,[bsSecPerTrack]  ; Patch the sector count
266                 mov [di-8],cl
267                 ; AX == 0 here
268                 int 13h                 ; Some BIOSes need this
269
270                 jmp short not_harddisk
271 ;
272 ; The drive number and possibly partition information was passed to us
273 ; by the BIOS or previous boot loader (MBR).  Current "best practice" is to
274 ; trust that rather than what the superblock contains.
275 ;
276 ; Would it be better to zero out bsHidden if we don't have a partition table?
277 ;
278 ; Note: di points to beyond the end of PartInfo
279 ;
280 harddisk:
281                 test byte [di-16],7Fh   ; Sanity check: "active flag" should
282                 jnz no_partition        ; be 00 or 80
283                 mov eax,[di-8]          ; Partition offset (dword)
284                 mov [bsHidden],eax
285 no_partition:
286 ;
287 ; Get disk drive parameters (don't trust the superblock.)  Don't do this for
288 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
289 ; what the *drive* supports, not about the *media*.  Fortunately floppy disks
290 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
291 ;
292                 ; DL == drive # still
293                 mov ah,08h
294                 int 13h
295                 jc no_driveparm
296                 and ah,ah
297                 jnz no_driveparm
298                 shr dx,8
299                 inc dx                  ; Contains # of heads - 1
300                 mov [bsHeads],dx
301                 and cx,3fh
302                 mov [bsSecPerTrack],cx
303 no_driveparm:
304 not_harddisk:
305 ;
306 ; Ready to enable interrupts, captain
307 ;
308                 sti
309
310 ;
311 ; Do we have EBIOS (EDD)?
312 ;
313 eddcheck:
314                 mov bx,55AAh
315                 mov ah,41h              ; EDD existence query
316                 mov dl,[DriveNumber]
317                 int 13h
318                 jc .noedd
319                 cmp bx,0AA55h
320                 jne .noedd
321                 test cl,1               ; Extended disk access functionality set
322                 jz .noedd
323                 ;
324                 ; We have EDD support...
325                 ;
326                 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
327 .noedd:
328
329 ;
330 ; Load the first sector of LDLINUX.SYS; this used to be all proper
331 ; with parsing the superblock and root directory; it doesn't fit
332 ; together with EBIOS support, unfortunately.
333 ;
334                 mov eax,[FirstSector]   ; Sector start
335                 mov bx,ldlinux_sys      ; Where to load it
336                 call getonesec
337
338                 ; Some modicum of integrity checking
339                 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
340                 jne kaboom
341
342                 ; Go for it...
343                 jmp ldlinux_ent
344
345 ;
346 ; getonesec: get one disk sector
347 ;
348 getonesec:
349                 mov bp,1                ; One sector
350                 ; Fall through
351
352 ;
353 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
354 ;            number in EAX into the buffer at ES:BX.  We try to optimize
355 ;            by loading up to a whole track at a time, but the user
356 ;            is responsible for not crossing a 64K boundary.
357 ;            (Yes, BP is weird for a count, but it was available...)
358 ;
359 ;            On return, BX points to the first byte after the transferred
360 ;            block.
361 ;
362 ;            This routine assumes CS == DS, and trashes most registers.
363 ;
364 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
365 ; that is dead from that point; this saves space.  However, please keep
366 ; the order to dst,src to keep things sane.
367 ;
368 getlinsec:
369                 add eax,[bsHidden]              ; Add partition offset
370                 xor edx,edx                     ; Zero-extend LBA (eventually allow 64 bits)
371
372 .jmp:           jmp strict short getlinsec_cbios
373
374 ;
375 ; getlinsec_ebios:
376 ;
377 ; getlinsec implementation for EBIOS (EDD)
378 ;
379 getlinsec_ebios:
380 .loop:
381                 push bp                         ; Sectors left
382 .retry2:
383                 call maxtrans                   ; Enforce maximum transfer size
384                 movzx edi,bp                    ; Sectors we are about to read
385                 mov cx,retry_count
386 .retry:
387
388                 ; Form DAPA on stack
389                 push edx
390                 push eax
391                 push es
392                 push bx
393                 push di
394                 push word 16
395                 mov si,sp
396                 pushad
397                 mov dl,[DriveNumber]
398                 push ds
399                 push ss
400                 pop ds                          ; DS <- SS
401                 mov ah,42h                      ; Extended Read
402                 int 13h
403                 pop ds
404                 popad
405                 lea sp,[si+16]                  ; Remove DAPA
406                 jc .error
407                 pop bp
408                 add eax,edi                     ; Advance sector pointer
409                 sub bp,di                       ; Sectors left
410                 shl di,SECTOR_SHIFT             ; 512-byte sectors
411                 add bx,di                       ; Advance buffer pointer
412                 and bp,bp
413                 jnz .loop
414
415                 ret
416
417 .error:
418                 ; Some systems seem to get "stuck" in an error state when
419                 ; using EBIOS.  Doesn't happen when using CBIOS, which is
420                 ; good, since some other systems get timeout failures
421                 ; waiting for the floppy disk to spin up.
422
423                 pushad                          ; Try resetting the device
424                 xor ax,ax
425                 mov dl,[DriveNumber]
426                 int 13h
427                 popad
428                 loop .retry                     ; CX-- and jump if not zero
429
430                 ;shr word [MaxTransfer],1       ; Reduce the transfer size
431                 ;jnz .retry2
432
433                 ; Total failure.  Try falling back to CBIOS.
434                 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
435                 ;mov byte [MaxTransfer],63      ; Max possibe CBIOS transfer
436
437                 pop bp
438                 ; ... fall through ...
439
440 ;
441 ; getlinsec_cbios:
442 ;
443 ; getlinsec implementation for legacy CBIOS
444 ;
445 getlinsec_cbios:
446 .loop:
447                 push edx
448                 push eax
449                 push bp
450                 push bx
451
452                 movzx esi,word [bsSecPerTrack]
453                 movzx edi,word [bsHeads]
454                 ;
455                 ; Dividing by sectors to get (track,sector): we may have
456                 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
457                 ;
458                 div esi
459                 xor cx,cx
460                 xchg cx,dx              ; CX <- sector index (0-based)
461                                         ; EDX <- 0
462                 ; eax = track #
463                 div edi                 ; Convert track to head/cyl
464
465                 ; We should test this, but it doesn't fit...
466                 ; cmp eax,1023
467                 ; ja .error
468
469                 ;
470                 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
471                 ; BP = sectors to transfer, SI = bsSecPerTrack,
472                 ; ES:BX = data target
473                 ;
474
475                 call maxtrans                   ; Enforce maximum transfer size
476
477                 ; Must not cross track boundaries, so BP <= SI-CX
478                 sub si,cx
479                 cmp bp,si
480                 jna .bp_ok
481                 mov bp,si
482 .bp_ok:
483
484                 shl ah,6                ; Because IBM was STOOPID
485                                         ; and thought 8 bits were enough
486                                         ; then thought 10 bits were enough...
487                 inc cx                  ; Sector numbers are 1-based, sigh
488                 or cl,ah
489                 mov ch,al
490                 mov dh,dl
491                 mov dl,[DriveNumber]
492                 xchg ax,bp              ; Sector to transfer count
493                 mov ah,02h              ; Read sectors
494                 mov bp,retry_count
495 .retry:
496                 pushad
497                 int 13h
498                 popad
499                 jc .error
500 .resume:
501                 movzx ecx,al            ; ECX <- sectors transferred
502                 shl ax,SECTOR_SHIFT     ; Convert sectors in AL to bytes in AX
503                 pop bx
504                 add bx,ax
505                 pop bp
506                 pop eax
507                 pop edx
508                 add eax,ecx
509                 sub bp,cx
510                 jnz .loop
511                 ret
512
513 .error:
514                 dec bp
515                 jnz .retry
516
517                 xchg ax,bp              ; Sectors transferred <- 0
518                 shr word [MaxTransfer],1
519                 jnz .resume
520                 ; Fall through to disk_error
521
522 ;
523 ; kaboom: write a message and bail out.
524 ;
525 disk_error:
526 kaboom:
527                 xor si,si
528                 mov ss,si
529                 mov sp,StackBuf-4       ; Reset stack
530                 mov ds,si               ; Reset data segment
531                 pop dword [fdctab]      ; Restore FDC table
532 .patch:                                 ; When we have full code, intercept here
533                 mov si,bailmsg
534
535                 ; Write error message, this assumes screen page 0
536 .loop:          lodsb
537                 and al,al
538                 jz .done
539                 mov ah,0Eh              ; Write to screen as TTY
540                 mov bx,0007h            ; Attribute
541                 int 10h
542                 jmp short .loop
543 .done:
544                 cbw                     ; AH <- 0
545                 int 16h                 ; Wait for keypress
546                 int 19h                 ; And try once more to boot...
547 .norge:         jmp short .norge        ; If int 19h returned; this is the end
548
549 ;
550 ; Truncate BP to MaxTransfer
551 ;
552 maxtrans:
553                 cmp bp,[MaxTransfer]
554                 jna .ok
555                 mov bp,[MaxTransfer]
556 .ok:            ret
557
558 ;
559 ; Error message on failure
560 ;
561 bailmsg:        db 'Boot error', 0Dh, 0Ah, 0
562
563                 ; This fails if the boot sector overflows
564                 zb 1F8h-($-$$)
565
566 FirstSector     dd 0xDEADBEEF                   ; Location of sector 1
567 MaxTransfer     dw 0x007F                       ; Max transfer size
568 bootsignature   dw 0AA55h
569
570 ;
571 ; ===========================================================================
572 ;  End of boot sector
573 ; ===========================================================================
574 ;  Start of LDLINUX.SYS
575 ; ===========================================================================
576
577 ldlinux_sys:
578
579 syslinux_banner db 0Dh, 0Ah
580 %if IS_MDSLINUX
581                 db 'MDSLINUX '
582 %else
583                 db 'SYSLINUX '
584 %endif
585                 db version_str, ' ', date, ' ', 0
586                 db 0Dh, 0Ah, 1Ah        ; EOF if we "type" this in DOS
587
588                 align 8, db 0
589 ldlinux_magic   dd LDLINUX_MAGIC
590                 dd LDLINUX_MAGIC^HEXDATE
591
592 ;
593 ; This area is patched by the installer.  It is found by looking for
594 ; LDLINUX_MAGIC, plus 8 bytes.
595 ;
596 patch_area:
597 LDLDwords       dw 0            ; Total dwords starting at ldlinux_sys
598 LDLSectors      dw 0            ; Number of sectors - (bootsec+this sec)
599 CheckSum        dd 0            ; Checksum starting at ldlinux_sys
600                                 ; value = LDLINUX_MAGIC - [sum of dwords]
601
602 ; Space for up to 64 sectors, the theoretical maximum
603 SectorPtrs      times 64 dd 0
604
605 ldlinux_ent:
606 ;
607 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
608 ; instead of 0000:7C00 and the like.  We don't want to add anything
609 ; more to the boot sector, so it is written to not assume a fixed
610 ; value in CS, but we don't want to deal with that anymore from now
611 ; on.
612 ;
613                 jmp 0:.next
614 .next:
615
616 ;
617 ; Tell the user we got this far
618 ;
619                 mov si,syslinux_banner
620                 call writestr
621
622 ;
623 ; Tell the user if we're using EBIOS or CBIOS
624 ;
625 print_bios:
626                 mov si,cbios_name
627                 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
628                 jne .cbios
629                 mov si,ebios_name
630 .cbios:
631                 mov [BIOSName],si
632                 call writestr
633
634                 section .bss
635 %define HAVE_BIOSNAME 1
636 BIOSName        resw 1
637
638                 section .text
639 ;
640 ; Now we read the rest of LDLINUX.SYS.  Don't bother loading the first
641 ; sector again, though.
642 ;
643 load_rest:
644                 mov si,SectorPtrs
645                 mov bx,7C00h+2*SECTOR_SIZE      ; Where we start loading
646                 mov cx,[LDLSectors]
647
648 .get_chunk:
649                 jcxz .done
650                 xor bp,bp
651                 lodsd                           ; First sector of this chunk
652
653                 mov edx,eax
654
655 .make_chunk:
656                 inc bp
657                 dec cx
658                 jz .chunk_ready
659                 inc edx                         ; Next linear sector
660                 cmp [si],edx                    ; Does it match
661                 jnz .chunk_ready                ; If not, this is it
662                 add si,4                        ; If so, add sector to chunk
663                 jmp short .make_chunk
664
665 .chunk_ready:
666                 call getlinsecsr
667                 shl bp,SECTOR_SHIFT
668                 add bx,bp
669                 jmp .get_chunk
670
671 .done:
672
673 ;
674 ; All loaded up, verify that we got what we needed.
675 ; Note: the checksum field is embedded in the checksum region, so
676 ; by the time we get to the end it should all cancel out.
677 ;
678 verify_checksum:
679                 mov si,ldlinux_sys
680                 mov cx,[LDLDwords]
681                 mov edx,-LDLINUX_MAGIC
682 .checksum:
683                 lodsd
684                 add edx,eax
685                 loop .checksum
686
687                 and edx,edx                     ; Should be zero
688                 jz all_read                     ; We're cool, go for it!
689
690 ;
691 ; Uh-oh, something went bad...
692 ;
693                 mov si,checksumerr_msg
694                 call writestr
695                 jmp kaboom
696
697 ;
698 ; -----------------------------------------------------------------------------
699 ; Subroutines that have to be in the first sector
700 ; -----------------------------------------------------------------------------
701
702 ;
703 ;
704 ; writestr: write a null-terminated string to the console
705 ;           This assumes we're on page 0.  This is only used for early
706 ;           messages, so it should be OK.
707 ;
708 writestr:
709 .loop:          lodsb
710                 and al,al
711                 jz .return
712                 mov ah,0Eh              ; Write to screen as TTY
713                 mov bx,0007h            ; Attribute
714                 int 10h
715                 jmp short .loop
716 .return:        ret
717
718
719 ; getlinsecsr: save registers, call getlinsec, restore registers
720 ;
721 getlinsecsr:    pushad
722                 call getlinsec
723                 popad
724                 ret
725
726 ;
727 ; Checksum error message
728 ;
729 checksumerr_msg db ' Load error - ', 0  ; Boot failed appended
730
731 ;
732 ; BIOS type string
733 ;
734 cbios_name      db 'CBIOS', 0
735 ebios_name      db 'EBIOS', 0
736
737 ;
738 ; Debug routine
739 ;
740 %ifdef debug
741 safedumpregs:
742                 cmp word [Debug_Magic],0D00Dh
743                 jnz nc_return
744                 jmp dumpregs
745 %endif
746
747 rl_checkpt      equ $                           ; Must be <= 8000h
748
749 rl_checkpt_off  equ ($-$$)
750 %ifndef DEPEND
751 %if rl_checkpt_off > 400h
752 %error "Sector 1 overflow"
753 %endif
754 %endif
755
756 ; ----------------------------------------------------------------------------
757 ;  End of code and data that have to be in the first sector
758 ; ----------------------------------------------------------------------------
759
760 all_read:
761 ;
762 ; Let the user (and programmer!) know we got this far.  This used to be
763 ; in Sector 1, but makes a lot more sense here.
764 ;
765                 mov si,copyright_str
766                 call writestr
767
768
769 ;
770 ; Insane hack to expand the superblock to dwords
771 ;
772 expand_super:
773                 xor eax,eax
774                 mov si,superblock
775                 mov di,SuperInfo
776                 mov cx,superinfo_size
777 .loop:
778                 lodsw
779                 dec si
780                 stosd                           ; Store expanded word
781                 xor ah,ah
782                 stosd                           ; Store expanded byte
783                 loop .loop
784
785 ;
786 ; Compute some information about this filesystem.
787 ;
788
789 ; First, generate the map of regions
790 genfatinfo:
791                 mov edx,[bxSectors]
792                 and dx,dx
793                 jnz .have_secs
794                 mov edx,[bsHugeSectors]
795 .have_secs:
796                 mov [TotalSectors],edx
797
798                 add edx,eax
799                 mov [EndSector],edx
800
801                 mov eax,[bxResSectors]
802                 mov [FAT],eax                   ; Beginning of FAT
803                 mov edx,[bxFATsecs]
804                 and dx,dx
805                 jnz .have_fatsecs
806                 mov edx,[bootsec+36]            ; FAT32 BPB_FATsz32
807 .have_fatsecs:
808                 imul edx,[bxFATs]
809                 add eax,edx
810                 mov [RootDirArea],eax           ; Beginning of root directory
811                 mov [RootDir],eax               ; For FAT12/16 == root dir location
812
813                 mov edx,[bxRootDirEnts]
814                 add dx,SECTOR_SIZE/32-1
815                 shr dx,SECTOR_SHIFT-5
816                 mov [RootDirSize],edx
817                 add eax,edx
818                 mov [DataArea],eax              ; Beginning of data area
819
820 ; Next, generate a cluster size shift count and mask
821                 mov eax,[bxSecPerClust]
822                 bsr cx,ax
823                 mov [ClustShift],cl
824                 push cx
825                 add cl,9
826                 mov [ClustByteShift],cl
827                 pop cx
828                 dec ax
829                 mov [ClustMask],eax
830                 inc ax
831                 shl eax,9
832                 mov [ClustSize],eax
833
834 ;
835 ; FAT12, FAT16 or FAT28^H^H32?  This computation is fscking ridiculous.
836 ;
837 getfattype:
838                 mov eax,[EndSector]
839                 sub eax,[DataArea]
840                 shr eax,cl                      ; cl == ClustShift
841                 mov cl,nextcluster_fat12-(nextcluster+2)
842                 cmp eax,4085                    ; FAT12 limit
843                 jb .setsize
844                 mov cl,nextcluster_fat16-(nextcluster+2)
845                 cmp eax,65525                   ; FAT16 limit
846                 jb .setsize
847                 ;
848                 ; FAT32, root directory is a cluster chain
849                 ;
850                 mov cl,[ClustShift]
851                 mov eax,[bootsec+44]            ; Root directory cluster
852                 sub eax,2
853                 shl eax,cl
854                 add eax,[DataArea]
855                 mov [RootDir],eax
856                 mov cl,nextcluster_fat28-(nextcluster+2)
857 .setsize:
858                 mov byte [nextcluster+1],cl
859
860 ;
861 ; Common initialization code
862 ;
863 %include "cpuinit.inc"
864 %include "init.inc"
865
866 ;
867 ; Clear Files structures
868 ;
869                 mov di,Files
870                 mov cx,(MAX_OPEN*open_file_t_size)/4
871                 xor eax,eax
872                 rep stosd
873
874 ;
875 ; Initialize the metadata cache
876 ;
877                 call initcache
878
879 ;
880 ; Now, everything is "up and running"... patch kaboom for more
881 ; verbosity and using the full screen system
882 ;
883                 ; E9 = JMP NEAR
884                 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
885
886 ;
887 ; Now we're all set to start with our *real* business.  First load the
888 ; configuration file (if any) and parse it.
889 ;
890 ; In previous versions I avoided using 32-bit registers because of a
891 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
892 ; random.  I figure, though, that if there are any of those still left
893 ; they probably won't be trying to install Linux on them...
894 ;
895 ; The code is still ripe with 16-bitisms, though.  Not worth the hassle
896 ; to take'm out.  In fact, we may want to put them back if we're going
897 ; to boot ELKS at some point.
898 ;
899
900 ;
901 ; Load configuration file
902 ;
903                 mov di,syslinux_cfg
904                 call open
905                 jz no_config_file
906
907 ;
908 ; Now we have the config file open.  Parse the config file and
909 ; run the user interface.
910 ;
911 %include "ui.inc"
912
913 ;
914 ; Linux kernel loading code is common.
915 ;
916 %include "runkernel.inc"
917
918 ;
919 ; COMBOOT-loading code
920 ;
921 %include "comboot.inc"
922 %include "com32.inc"
923 %include "cmdline.inc"
924
925 ;
926 ; Boot sector loading code
927 ;
928 %include "bootsect.inc"
929
930 ;
931 ; Abort loading code
932 ;
933 %include "abort.inc"
934
935 ;
936 ; allocate_file: Allocate a file structure
937 ;
938 ;               If successful:
939 ;                 ZF set
940 ;                 BX = file pointer
941 ;               In unsuccessful:
942 ;                 ZF clear
943 ;
944 allocate_file:
945                 TRACER 'a'
946                 push cx
947                 mov bx,Files
948                 mov cx,MAX_OPEN
949 .check:         cmp dword [bx], byte 0
950                 je .found
951                 add bx,open_file_t_size         ; ZF = 0
952                 loop .check
953                 ; ZF = 0 if we fell out of the loop
954 .found:         pop cx
955                 ret
956
957 ;
958 ; searchdir:
959 ;            Search the root directory for a pre-mangled filename in DS:DI.
960 ;
961 ;            NOTE: This file considers finding a zero-length file an
962 ;            error.  This is so we don't have to deal with that special
963 ;            case elsewhere in the program (most loops have the test
964 ;            at the end).
965 ;
966 ;            If successful:
967 ;               ZF clear
968 ;               SI      = file pointer
969 ;               DX:AX   = file length in bytes
970 ;            If unsuccessful
971 ;               ZF set
972 ;
973
974 searchdir:
975                 push bx
976                 call allocate_file
977                 jnz .alloc_failure
978
979                 push cx
980                 push gs
981                 push es
982                 push ds
983                 pop es                          ; ES = DS
984
985                 mov eax,[RootDir]               ; First root directory sector
986
987 .scansector:
988                 call getcachesector
989                 ; GS:SI now points to this sector
990
991                 mov cx,SECTOR_SIZE/32           ; 32 == directory entry size
992 .scanentry:
993                 cmp byte [gs:si],0
994                 jz .failure                     ; Hit directory high water mark
995                 push cx
996                 push si
997                 push di
998                 mov cx,11
999                 gs repe cmpsb
1000                 pop di
1001                 pop si
1002                 pop cx
1003                 jz .found
1004                 add si,32
1005                 loop .scanentry
1006
1007                 call nextsector
1008                 jnc .scansector                 ; CF is set if we're at end
1009
1010                 ; If we get here, we failed
1011 .failure:
1012                 pop es
1013                 pop gs
1014                 pop cx
1015 .alloc_failure:
1016                 pop bx
1017                 xor eax,eax                     ; ZF <- 1
1018                 ret
1019 .found:
1020                 mov eax,[gs:si+28]              ; File size
1021                 add eax,SECTOR_SIZE-1
1022                 shr eax,SECTOR_SHIFT
1023                 jz .failure                     ; Zero-length file
1024                 mov [bx+4],eax
1025
1026                 mov cl,[ClustShift]
1027                 mov dx,[gs:si+20]               ; High cluster word
1028                 shl edx,16
1029                 mov dx,[gs:si+26]               ; Low cluster word
1030                 sub edx,2
1031                 shl edx,cl
1032                 add edx,[DataArea]
1033                 mov [bx],edx                    ; Starting sector
1034
1035                 mov eax,[gs:si+28]              ; File length again
1036                 mov dx,[gs:si+30]               ; 16-bitism, sigh
1037                 mov si,bx
1038                 and eax,eax                     ; ZF <- 0
1039
1040                 pop es
1041                 pop gs
1042                 pop cx
1043                 pop bx
1044                 ret
1045
1046 ;
1047 ;
1048 ; kaboom2: once everything is loaded, replace the part of kaboom
1049 ;          starting with "kaboom.patch" with this part
1050
1051 kaboom2:
1052                 mov si,err_bootfailed
1053                 call cwritestr
1054                 call getchar
1055                 call vgaclearmode
1056                 int 19h                 ; And try once more to boot...
1057 .norge:         jmp short .norge        ; If int 19h returned; this is the end
1058
1059 ;
1060 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
1061 ;              to by ES:DI; ends on encountering any whitespace
1062 ;
1063
1064 mangle_name:
1065                 mov cx,11                       ; # of bytes to write
1066 mn_loop:
1067                 lodsb
1068                 cmp al,' '                      ; If control or space, end
1069                 jna mn_end
1070                 cmp al,'.'                      ; Period -> space-fill
1071                 je mn_is_period
1072                 cmp al,'a'
1073                 jb mn_not_lower
1074                 cmp al,'z'
1075                 ja mn_not_uslower
1076                 sub al,020h
1077                 jmp short mn_not_lower
1078 mn_is_period:   mov al,' '                      ; We need to space-fill
1079 mn_period_loop: cmp cx,3                        ; If <= 3 characters left
1080                 jbe mn_loop                     ; Just ignore it
1081                 stosb                           ; Otherwise, write a period
1082                 loop mn_period_loop             ; Dec CX and (always) jump
1083 mn_not_uslower: cmp al,ucase_low
1084                 jb mn_not_lower
1085                 cmp al,ucase_high
1086                 ja mn_not_lower
1087                 mov bx,ucase_tab-ucase_low
1088                 cs xlatb
1089 mn_not_lower:   stosb
1090                 loop mn_loop                    ; Don't continue if too long
1091 mn_end:
1092                 mov al,' '                      ; Space-fill name
1093                 rep stosb                       ; Doesn't do anything if CX=0
1094                 ret                             ; Done
1095
1096 ;
1097 ; Upper-case table for extended characters; this is technically code page 865,
1098 ; but code page 437 users will probably not miss not being able to use the
1099 ; cent sign in kernel images too much :-)
1100 ;
1101 ; The table only covers the range 129 to 164; the rest we can deal with.
1102 ;
1103 ucase_low       equ 129
1104 ucase_high      equ 164
1105 ucase_tab       db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1106                 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1107                 db 157, 156, 157, 158, 159, 'AIOU', 165
1108
1109 ;
1110 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1111 ;                filename to the conventional representation.  This is needed
1112 ;                for the BOOT_IMAGE= parameter for the kernel.
1113 ;                NOTE: A 13-byte buffer is mandatory, even if the string is
1114 ;                known to be shorter.
1115 ;
1116 ;                DS:SI -> input mangled file name
1117 ;                ES:DI -> output buffer
1118 ;
1119 ;                On return, DI points to the first byte after the output name,
1120 ;                which is set to a null byte.
1121 ;
1122 unmangle_name:
1123                 push si                 ; Save pointer to original name
1124                 mov cx,8
1125                 mov bp,di
1126 un_copy_body:   lodsb
1127                 call lower_case
1128                 stosb
1129                 cmp al,' '
1130                 jbe un_cb_space
1131                 mov bp,di               ; Position of last nonblank+1
1132 un_cb_space:    loop un_copy_body
1133                 mov di,bp
1134                 mov al,'.'              ; Don't save
1135                 stosb
1136                 mov cx,3
1137 un_copy_ext:    lodsb
1138                 call lower_case
1139                 stosb
1140                 cmp al,' '
1141                 jbe un_ce_space
1142                 mov bp,di
1143 un_ce_space:    loop un_copy_ext
1144                 mov di,bp
1145                 mov byte [es:di], 0
1146                 pop si
1147                 ret
1148
1149 ;
1150 ; lower_case: Lower case a character in AL
1151 ;
1152 lower_case:
1153                 cmp al,'A'
1154                 jb lc_ret
1155                 cmp al,'Z'
1156                 ja lc_1
1157                 or al,20h
1158                 ret
1159 lc_1:           cmp al,lcase_low
1160                 jb lc_ret
1161                 cmp al,lcase_high
1162                 ja lc_ret
1163                 push bx
1164                 mov bx,lcase_tab-lcase_low
1165                 cs xlatb
1166                 pop bx
1167 lc_ret:         ret
1168
1169 ;
1170 ; getfssec_edx: Get multiple sectors from a file
1171 ;
1172 ;       This routine makes sure the subtransfers do not cross a 64K boundary,
1173 ;       and will correct the situation if it does, UNLESS *sectors* cross
1174 ;       64K boundaries.
1175 ;
1176 ;       ES:BX   -> Buffer
1177 ;       EDX     -> Current sector number
1178 ;       CX      -> Sector count (0FFFFh = until end of file)
1179 ;                  Must not exceed the ES segment
1180 ;       Returns EDX=0, CF=1 on EOF (not necessarily error)
1181 ;       All arguments are advanced to reflect data read.
1182 ;
1183 getfssec_edx:
1184                 push ebp
1185                 push eax
1186 .getfragment:
1187                 xor ebp,ebp                     ; Fragment sector count
1188                 push edx                        ; Starting sector pointer
1189 .getseccnt:
1190                 inc bp
1191                 dec cx
1192                 jz .do_read
1193                 xor eax,eax
1194                 mov ax,es
1195                 shl ax,4
1196                 add ax,bx                       ; Now AX = how far into 64K block we are
1197                 not ax                          ; Bytes left in 64K block
1198                 inc eax
1199                 shr eax,SECTOR_SHIFT            ; Sectors left in 64K block
1200                 cmp bp,ax
1201                 jnb .do_read                    ; Unless there is at least 1 more sector room...
1202                 mov eax,edx                     ; Current sector
1203                 inc edx                         ; Predict it's the linearly next sector
1204                 call nextsector
1205                 jc .do_read
1206                 cmp edx,eax                     ; Did it match?
1207                 jz .getseccnt
1208 .do_read:
1209                 pop eax                         ; Starting sector pointer
1210                 call getlinsecsr
1211                 lea eax,[eax+ebp-1]             ; This is the last sector actually read
1212                 shl bp,9
1213                 add bx,bp                       ; Adjust buffer pointer
1214                 call nextsector
1215                 jc .eof
1216                 mov edx,eax
1217                 and cx,cx
1218                 jnz .getfragment
1219 .done:
1220                 pop eax
1221                 pop ebp
1222                 ret
1223 .eof:
1224                 xor edx,edx
1225                 stc
1226                 jmp .done
1227
1228 ;
1229 ; getfssec: Get multiple sectors from a file
1230 ;
1231 ;       Same as above, except SI is a pointer to a open_file_t
1232 ;
1233 ;       ES:BX   -> Buffer
1234 ;       DS:SI   -> Pointer to open_file_t
1235 ;       CX      -> Sector count (0FFFFh = until end of file)
1236 ;                  Must not exceed the ES segment
1237 ;       Returns CF=1 on EOF (not necessarily error)
1238 ;       All arguments are advanced to reflect data read.
1239 ;
1240 getfssec:
1241                 push edx
1242                 movzx edx,cx
1243                 cmp edx,[si+4]
1244                 jbe .sizeok
1245                 mov edx,[si+4]
1246                 mov cx,dx
1247 .sizeok:
1248                 sub [si+4],edx
1249                 mov edx,[si]
1250                 call getfssec_edx
1251                 mov [si],edx
1252                 pop edx
1253                 ret
1254
1255 ;
1256 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1257 ;              pointed at in the FAT tables.  CF=0 on return if end of file.
1258 ;
1259 nextcluster:
1260                 jmp strict short nextcluster_fat28      ; This gets patched
1261
1262 nextcluster_fat12:
1263                 push eax
1264                 push edx
1265                 push bx
1266                 push cx
1267                 push si
1268                 mov edx,edi
1269                 shr edi,1
1270                 pushf                   ; Save the shifted-out LSB (=CF)
1271                 add edx,edi
1272                 mov eax,edx
1273                 shr eax,9
1274                 call getfatsector
1275                 mov bx,dx
1276                 and bx,1FFh
1277                 mov cl,[gs:si+bx]
1278                 inc edx
1279                 mov eax,edx
1280                 shr eax,9
1281                 call getfatsector
1282                 mov bx,dx
1283                 and bx,1FFh
1284                 mov ch,[gs:si+bx]
1285                 popf
1286                 jnc .even
1287                 shr cx,4
1288 .even:          and cx,0FFFh
1289                 movzx edi,cx
1290                 cmp di,0FF0h
1291                 pop si
1292                 pop cx
1293                 pop bx
1294                 pop edx
1295                 pop eax
1296                 ret
1297
1298 ;
1299 ; FAT16 decoding routine.
1300 ;
1301 nextcluster_fat16:
1302                 push eax
1303                 push si
1304                 push bx
1305                 mov eax,edi
1306                 shr eax,SECTOR_SHIFT-1
1307                 call getfatsector
1308                 mov bx,di
1309                 add bx,bx
1310                 and bx,1FEh
1311                 movzx edi,word [gs:si+bx]
1312                 cmp di,0FFF0h
1313                 pop bx
1314                 pop si
1315                 pop eax
1316                 ret
1317 ;
1318 ; FAT28 ("FAT32") decoding routine.
1319 ;
1320 nextcluster_fat28:
1321                 push eax
1322                 push si
1323                 push bx
1324                 mov eax,edi
1325                 shr eax,SECTOR_SHIFT-2
1326                 call getfatsector
1327                 mov bx,di
1328                 add bx,bx
1329                 add bx,bx
1330                 and bx,1FCh
1331                 mov edi,dword [gs:si+bx]
1332                 and edi,0FFFFFFFh       ; 28 bits only
1333                 cmp edi,0FFFFFF0h
1334                 pop bx
1335                 pop si
1336                 pop eax
1337                 ret
1338
1339 ;
1340 ; nextsector:   Given a sector in EAX on input, return the next sector
1341 ;               of the same filesystem object, which may be the root
1342 ;               directory or a cluster chain.  Returns  EOF.
1343 ;
1344 ;               Assumes CS == DS.
1345 ;
1346 nextsector:
1347                 push edi
1348                 push edx
1349                 mov edx,[DataArea]
1350                 mov edi,eax
1351                 sub edi,edx
1352                 jae .isdata
1353
1354                 ; Root directory
1355                 inc eax
1356                 cmp eax,edx
1357                 cmc
1358                 jmp .done
1359
1360 .isdata:
1361                 not edi
1362                 test edi,[ClustMask]
1363                 jz .endcluster
1364
1365                 ; It's not the final sector in a cluster
1366                 inc eax
1367                 jmp .done
1368
1369 .endcluster:
1370                 push gs                 ; nextcluster trashes gs
1371                 push cx
1372                 not edi
1373                 mov cl,[ClustShift]
1374                 shr edi,cl
1375                 add edi,2
1376
1377                 ; Now EDI contains the cluster number
1378                 call nextcluster
1379                 cmc
1380                 jc .exit                ; There isn't anything else...
1381
1382                 ; New cluster number now in EDI
1383                 sub edi,2
1384                 shl edi,cl              ; CF <- 0, unless something is very wrong
1385                 lea eax,[edi+edx]
1386 .exit:
1387                 pop cx
1388                 pop gs
1389 .done:
1390                 pop edx
1391                 pop edi
1392                 ret
1393
1394 ;
1395 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1396 ;               and return a pointer in GS:SI, loading it if needed.
1397 ;
1398 ;               Assumes CS == DS.
1399 ;
1400 getfatsector:
1401                 add eax,[FAT]           ; FAT starting address
1402                 jmp getcachesector
1403
1404 ; -----------------------------------------------------------------------------
1405 ;  Common modules
1406 ; -----------------------------------------------------------------------------
1407
1408 %include "getc.inc"             ; getc et al
1409 %include "conio.inc"            ; Console I/O
1410 %include "plaincon.inc"         ; writechr
1411 %include "writestr.inc"         ; String output
1412 %include "configinit.inc"       ; Initialize configuration
1413 %include "parseconfig.inc"      ; High-level config file handling
1414 %include "parsecmd.inc"         ; Low-level config file handling
1415 %include "bcopy32.inc"          ; 32-bit bcopy
1416 %include "loadhigh.inc"         ; Load a file into high memory
1417 %include "font.inc"             ; VGA font stuff
1418 %include "graphics.inc"         ; VGA graphics
1419 %include "highmem.inc"          ; High memory sizing
1420 %include "strcpy.inc"           ; strcpy()
1421 %include "cache.inc"            ; Metadata disk cache
1422
1423 ; -----------------------------------------------------------------------------
1424 ;  Begin data section
1425 ; -----------------------------------------------------------------------------
1426
1427                 section .data
1428 ;
1429 ; Lower-case table for codepage 865
1430 ;
1431 lcase_low       equ 128
1432 lcase_high      equ 165
1433 lcase_tab       db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
1434                 db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
1435                 db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
1436                 db 161, 162, 163, 164, 164
1437
1438 copyright_str   db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1439                 db CR, LF, 0
1440 boot_prompt     db 'boot: ', 0
1441 wipe_char       db BS, ' ', BS, 0
1442 err_notfound    db 'Could not find kernel image: ',0
1443 err_notkernel   db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1444 err_noram       db 'It appears your computer has less than '
1445                 asciidec dosram_k
1446                 db 'K of low ("DOS")'
1447                 db CR, LF
1448                 db 'RAM.  Linux needs at least this amount to boot.  If you get'
1449                 db CR, LF
1450                 db 'this message in error, hold down the Ctrl key while'
1451                 db CR, LF
1452                 db 'booting, and I will take your word for it.', CR, LF, 0
1453 err_badcfg      db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1454 err_noparm      db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1455 err_noinitrd    db CR, LF, 'Could not find ramdisk image: ', 0
1456 err_nohighmem   db 'Not enough memory to load specified kernel.', CR, LF, 0
1457 err_highload    db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1458 err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
1459                 db CR, LF, 0
1460 err_notdos      db ': attempted DOS system call', CR, LF, 0
1461 err_comlarge    db 'COMBOOT image too large.', CR, LF, 0
1462 err_a20         db CR, LF, 'A20 gate not responding!', CR, LF, 0
1463 err_bootfailed  db CR, LF, 'Boot failed: please change disks and press '
1464                 db 'a key to continue.', CR, LF, 0
1465 ready_msg       db 'Ready.', CR, LF, 0
1466 crlfloading_msg db CR, LF
1467 loading_msg     db 'Loading ', 0
1468 dotdot_msg      db '.'
1469 dot_msg         db '.', 0
1470 aborted_msg     db ' aborted.'                  ; Fall through to crlf_msg!
1471 crlf_msg        db CR, LF
1472 null_msg        db 0
1473 crff_msg        db CR, FF, 0
1474 syslinux_cfg    db 'SYSLINUXCFG'                ; Mangled form
1475 ConfigName      db 'syslinux.cfg',0             ; Unmangled form
1476 %if IS_MDSLINUX
1477 manifest        db 'MANIFEST   '
1478 %endif
1479 ;
1480 ; Command line options we'd like to take a look at
1481 ;
1482 ; mem= and vga= are handled as normal 32-bit integer values
1483 initrd_cmd      db 'initrd='
1484 initrd_cmd_len  equ 7
1485
1486 ;
1487 ; Config file keyword table
1488 ;
1489 %include "keywords.inc"
1490
1491 ;
1492 ; Extensions to search for (in *forward* order).
1493 ;
1494 exten_table:    db 'CBT',0              ; COMBOOT (specific)
1495                 db 'BSS',0              ; Boot Sector (add superblock)
1496                 db 'BS ',0              ; Boot Sector
1497                 db 'COM',0              ; COMBOOT (same as DOS)
1498                 db 'C32',0              ; COM32
1499 exten_table_end:
1500                 dd 0, 0                 ; Need 8 null bytes here
1501
1502 ;
1503 ; Misc initialized (data) variables
1504 ;
1505 %ifdef debug                            ; This code for debugging only
1506 debug_magic     dw 0D00Dh               ; Debug code sentinel
1507 %endif
1508
1509                 alignb 4, db 0
1510 BufSafe         dw trackbufsize/SECTOR_SIZE     ; Clusters we can load into trackbuf
1511 BufSafeSec      dw trackbufsize/SECTOR_SIZE     ; = how many sectors?
1512 BufSafeBytes    dw trackbufsize         ; = how many bytes?
1513 EndOfGetCBuf    dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1514 %ifndef DEPEND
1515 %if ( trackbufsize % SECTOR_SIZE ) != 0
1516 %error trackbufsize must be a multiple of SECTOR_SIZE
1517 %endif
1518 %endif