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