Merge with syslinux-3.35
[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-2007   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 6                  ; log2(Max filename size Including final null)
34 FILENAME_MAX    equ (1<<FILENAME_MAX_LG2) ; Max mangled filename size
35 NULLFILE        equ 0                   ; 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_cfg1
904                 call open
905                 jnz .config_open
906                 mov di,syslinux_cfg2
907                 call open
908                 jnz .config_open
909                 mov di,syslinux_cfg3
910                 call open
911                 jz no_config_file
912 .config_open:
913                 mov eax,[PrevDir]       ; Make the directory with syslinux.cfg ...
914                 mov [CurrentDir],eax    ; ... the current directory
915
916 ;
917 ; Now we have the config file open.  Parse the config file and
918 ; run the user interface.
919 ;
920 %include "ui.inc"
921
922 ;
923 ; Linux kernel loading code is common.
924 ;
925 %include "runkernel.inc"
926
927 ;
928 ; COMBOOT-loading code
929 ;
930 %include "comboot.inc"
931 %include "com32.inc"
932 %include "cmdline.inc"
933
934 ;
935 ; Boot sector loading code
936 ;
937 %include "bootsect.inc"
938
939 ;
940 ; Abort loading code
941 ;
942 %include "abort.inc"
943
944 ;
945 ; allocate_file: Allocate a file structure
946 ;
947 ;               If successful:
948 ;                 ZF set
949 ;                 BX = file pointer
950 ;               In unsuccessful:
951 ;                 ZF clear
952 ;
953 allocate_file:
954                 TRACER 'a'
955                 push cx
956                 mov bx,Files
957                 mov cx,MAX_OPEN
958 .check:         cmp dword [bx], byte 0
959                 je .found
960                 add bx,open_file_t_size         ; ZF = 0
961                 loop .check
962                 ; ZF = 0 if we fell out of the loop
963 .found:         pop cx
964                 ret
965
966 ;
967 ; search_dos_dir:
968 ;            Search a specific directory for a pre-mangled filename in
969 ;            MangledBuf, in the directory starting in sector EAX.
970 ;
971 ;            NOTE: This file considers finding a zero-length file an
972 ;            error.  This is so we don't have to deal with that special
973 ;            case elsewhere in the program (most loops have the test
974 ;            at the end).
975 ;
976 ;            Assumes DS == ES == CS.
977 ;
978 ;            If successful:
979 ;               ZF clear
980 ;               SI      = file pointer
981 ;               EAX     = file length (MAY BE ZERO!)
982 ;               DL      = file attributes
983 ;            If unsuccessful
984 ;               ZF set
985 ;
986
987 search_dos_dir:
988                 push bx
989                 call allocate_file
990                 jnz .alloc_failure
991
992                 push cx
993                 push gs
994                 push es
995                 push ds
996                 pop es                          ; ES = DS
997
998 .scansector:
999                 ; EAX <- directory sector to scan
1000                 call getcachesector
1001                 ; GS:SI now points to this sector
1002
1003                 mov cx,SECTOR_SIZE/32           ; 32 == directory entry size
1004 .scanentry:
1005                 cmp byte [gs:si],0
1006                 jz .failure                     ; Hit directory high water mark
1007                 test byte [gs:si+11],8          ; Ignore volume labels and
1008                                                 ; VFAT long filename entries
1009                 jnz .nomatch
1010                 push cx
1011                 push si
1012                 push di
1013                 mov di,MangledBuf
1014                 mov cx,11
1015                 gs repe cmpsb
1016                 pop di
1017                 pop si
1018                 pop cx
1019                 jz .found
1020 .nomatch:
1021                 add si,32
1022                 loop .scanentry
1023
1024                 call nextsector
1025                 jnc .scansector                 ; CF is set if we're at end
1026
1027                 ; If we get here, we failed
1028 .failure:
1029                 pop es
1030                 pop gs
1031                 pop cx
1032 .alloc_failure:
1033                 pop bx
1034                 xor eax,eax                     ; ZF <- 1
1035                 ret
1036 .found:
1037                 mov eax,[gs:si+28]              ; File size
1038                 add eax,SECTOR_SIZE-1
1039                 shr eax,SECTOR_SHIFT
1040                 mov [bx+4],eax                  ; Sector count
1041
1042                 mov cl,[ClustShift]
1043                 mov dx,[gs:si+20]               ; High cluster word
1044                 shl edx,16
1045                 mov dx,[gs:si+26]               ; Low cluster word
1046                 sub edx,2
1047                 shl edx,cl
1048                 add edx,[DataArea]
1049                 mov [bx],edx                    ; Starting sector
1050
1051                 mov eax,[gs:si+28]              ; File length again
1052                 mov dl,[gs:si+11]               ; File attribute
1053                 mov si,bx                       ; File pointer...
1054                 and si,si                       ; ZF <- 0
1055
1056                 pop es
1057                 pop gs
1058                 pop cx
1059                 pop bx
1060                 ret
1061
1062 ;
1063 ; searchdir:
1064 ;
1065 ;       Open a file
1066 ;
1067 ;            On entry:
1068 ;               DS:DI   = filename
1069 ;            If successful:
1070 ;               ZF clear
1071 ;               SI              = file pointer
1072 ;               DX:AX or EAX    = file length in bytes
1073 ;            If unsuccessful
1074 ;               ZF set
1075 ;
1076 ; Assumes CS == DS == ES, and trashes BX and CX.
1077 ;
1078 searchdir:
1079                 mov eax,[CurrentDir]
1080                 cmp byte [di],'/'       ; Root directory?
1081                 jne .notroot
1082                 mov eax,[RootDir]
1083                 inc di
1084 .notroot:
1085
1086 .pathwalk:
1087                 push eax                ; <A> Current directory sector
1088                 mov si,di
1089 .findend:
1090                 lodsb
1091                 cmp al,' '
1092                 jbe .endpath
1093                 cmp al,'/'
1094                 jne .findend
1095 .endpath:
1096                 xchg si,di
1097                 pop eax                 ; <A> Current directory sector
1098
1099                 mov [PrevDir],eax       ; Remember last directory searched
1100
1101                 push di
1102                 call mangle_dos_name    ; MangledBuf <- component
1103                 call search_dos_dir
1104                 pop di
1105                 jz .notfound            ; Pathname component missing
1106
1107                 cmp byte [di-1],'/'     ; Do we expect a directory
1108                 je .isdir
1109
1110                 ; Otherwise, it should be a file
1111 .isfile:
1112                 test dl,18h             ; Subdirectory|Volume Label
1113                 jnz .badfile            ; If not a file, it's a bad thing
1114
1115                 ; SI and EAX are already set
1116                 mov edx,eax
1117                 shr edx,16              ; Old 16-bit remnant...
1118                 and eax,eax             ; EAX != 0
1119                 jz .badfile
1120                 ret                     ; Done!
1121
1122                 ; If we expected a directory, it better be one...
1123 .isdir:
1124                 test dl,10h             ; Subdirectory
1125                 jz .badfile
1126
1127                 xor eax,eax
1128                 xchg eax,[si+file_sector] ; Get sector number and free file structure
1129                 jmp .pathwalk           ; Walk the next bit of the path
1130
1131 .badfile:
1132                 xor eax,eax
1133                 mov [si],eax            ; Free file structure
1134
1135 .notfound:
1136                 xor eax,eax
1137                 xor dx,dx
1138                 ret
1139
1140                 section .bss
1141                 alignb 4
1142 CurrentDir      resd 1                  ; Current directory
1143 PrevDir         resd 1                  ; Last scanned directory
1144
1145                 section .text
1146
1147 ;
1148 ;
1149 ; kaboom2: once everything is loaded, replace the part of kaboom
1150 ;          starting with "kaboom.patch" with this part
1151
1152 kaboom2:
1153                 mov si,err_bootfailed
1154                 call cwritestr
1155                 call getchar
1156                 call vgaclearmode
1157                 int 19h                 ; And try once more to boot...
1158 .norge:         jmp short .norge        ; If int 19h returned; this is the end
1159
1160 ;
1161 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1162 ;              to by ES:DI; ends on encountering any whitespace.
1163 ;
1164 ;              This verifies that a filename is < FILENAME_MAX characters,
1165 ;              doesn't contain whitespace, zero-pads the output buffer,
1166 ;              and removes trailing dots and redundant slashes, plus changes
1167 ;              backslashes to forward slashes,
1168 ;              so "repe cmpsb" can do a compare, and the path-searching routine
1169 ;              gets a bit of an easier job.
1170 ;
1171 ;
1172 mangle_name:
1173                 push bx
1174                 xor ax,ax
1175                 mov cx,FILENAME_MAX-1
1176                 mov bx,di
1177
1178 .mn_loop:
1179                 lodsb
1180                 cmp al,' '                      ; If control or space, end
1181                 jna .mn_end
1182                 cmp al,'\'                      ; Backslash?
1183                 jne .mn_not_bs
1184                 mov al,'/'                      ; Change to forward slash
1185 .mn_not_bs:
1186                 cmp al,ah                       ; Repeated slash?
1187                 je .mn_skip
1188                 xor ah,ah
1189                 cmp al,'/'
1190                 jne .mn_ok
1191                 mov ah,al
1192 .mn_ok          stosb
1193 .mn_skip:       loop .mn_loop
1194 .mn_end:
1195                 cmp bx,di                       ; At the beginning of the buffer?
1196                 jbe .mn_zero
1197                 cmp byte [es:di-1],'.'          ; Terminal dot?
1198                 je .mn_kill
1199                 cmp byte [es:di-1],'/'          ; Terminal slash?
1200                 jne .mn_zero
1201 .mn_kill:       dec di                          ; If so, remove it
1202                 inc cx
1203                 jmp short .mn_end
1204 .mn_zero:
1205                 inc cx                          ; At least one null byte
1206                 xor ax,ax                       ; Zero-fill name
1207                 rep stosb
1208                 pop bx
1209                 ret                             ; Done
1210
1211 ;
1212 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1213 ;                filename to the conventional representation.  This is needed
1214 ;                for the BOOT_IMAGE= parameter for the kernel.
1215 ;                NOTE: A 13-byte buffer is mandatory, even if the string is
1216 ;                known to be shorter.
1217 ;
1218 ;                DS:SI -> input mangled file name
1219 ;                ES:DI -> output buffer
1220 ;
1221 ;                On return, DI points to the first byte after the output name,
1222 ;                which is set to a null byte.
1223 ;
1224 unmangle_name:  call strcpy
1225                 dec di                          ; Point to final null byte
1226                 ret
1227
1228 ;
1229 ; mangle_dos_name:
1230 ;               Mangle a DOS filename component pointed to by DS:SI
1231 ;               into [MangledBuf]; ends on encountering any whitespace or slash.
1232 ;               Assumes CS == DS == ES.
1233 ;
1234
1235 mangle_dos_name:
1236                 pusha
1237                 mov di,MangledBuf
1238
1239                 mov cx,11                       ; # of bytes to write
1240 .loop:
1241                 lodsb
1242                 cmp al,' '                      ; If control or space, end
1243                 jna .end
1244                 cmp al,'/'                      ; Slash, too
1245                 je .end
1246                 cmp al,'.'                      ; Period -> space-fill
1247                 je .is_period
1248                 cmp al,'a'
1249                 jb .not_lower
1250                 cmp al,'z'
1251                 ja .not_uslower
1252                 sub al,020h
1253                 jmp short .not_lower
1254 .is_period:     mov al,' '                      ; We need to space-fill
1255 .period_loop:   cmp cx,3                        ; If <= 3 characters left
1256                 jbe .loop                       ; Just ignore it
1257                 stosb                           ; Otherwise, write a period
1258                 loop .period_loop               ; Dec CX and (always) jump
1259 .not_uslower:   cmp al,ucase_low
1260                 jb .not_lower
1261                 cmp al,ucase_high
1262                 ja .not_lower
1263                 mov bx,ucase_tab-ucase_low
1264                 xlatb
1265 .not_lower:     stosb
1266                 loop .loop                      ; Don't continue if too long
1267 .end:
1268                 mov al,' '                      ; Space-fill name
1269                 rep stosb                       ; Doesn't do anything if CX=0
1270                 popa
1271                 ret                             ; Done
1272
1273                 section .bss
1274 MangledBuf      resb 11
1275
1276                 section .text
1277 ;
1278 ; Case tables for extended characters; this is technically code page 865,
1279 ; but code page 437 users will probably not miss not being able to use the
1280 ; cent sign in kernel images too much :-)
1281 ;
1282 ; The table only covers the range 129 to 164; the rest we can deal with.
1283 ;
1284                 section .data
1285
1286 ucase_low       equ 129
1287 ucase_high      equ 164
1288 ucase_tab       db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1289                 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1290                 db 157, 156, 157, 158, 159, 'AIOU', 165
1291
1292                 section .text
1293 ;
1294 ; getfssec_edx: Get multiple sectors from a file
1295 ;
1296 ;       This routine makes sure the subtransfers do not cross a 64K boundary,
1297 ;       and will correct the situation if it does, UNLESS *sectors* cross
1298 ;       64K boundaries.
1299 ;
1300 ;       ES:BX   -> Buffer
1301 ;       EDX     -> Current sector number
1302 ;       CX      -> Sector count (0FFFFh = until end of file)
1303 ;                  Must not exceed the ES segment
1304 ;       Returns EDX=0, CF=1 on EOF (not necessarily error)
1305 ;       All arguments are advanced to reflect data read.
1306 ;
1307 getfssec_edx:
1308                 push ebp
1309                 push eax
1310 .getfragment:
1311                 xor ebp,ebp                     ; Fragment sector count
1312                 push edx                        ; Starting sector pointer
1313 .getseccnt:
1314                 inc bp
1315                 dec cx
1316                 jz .do_read
1317                 xor eax,eax
1318                 mov ax,es
1319                 shl ax,4
1320                 add ax,bx                       ; Now AX = how far into 64K block we are
1321                 not ax                          ; Bytes left in 64K block
1322                 inc eax
1323                 shr eax,SECTOR_SHIFT            ; Sectors left in 64K block
1324                 cmp bp,ax
1325                 jnb .do_read                    ; Unless there is at least 1 more sector room...
1326                 mov eax,edx                     ; Current sector
1327                 inc edx                         ; Predict it's the linearly next sector
1328                 call nextsector
1329                 jc .do_read
1330                 cmp edx,eax                     ; Did it match?
1331                 jz .getseccnt
1332 .do_read:
1333                 pop eax                         ; Starting sector pointer
1334                 call getlinsecsr
1335                 lea eax,[eax+ebp-1]             ; This is the last sector actually read
1336                 shl bp,9
1337                 add bx,bp                       ; Adjust buffer pointer
1338                 call nextsector
1339                 jc .eof
1340                 mov edx,eax
1341                 and cx,cx
1342                 jnz .getfragment
1343 .done:
1344                 pop eax
1345                 pop ebp
1346                 ret
1347 .eof:
1348                 xor edx,edx
1349                 stc
1350                 jmp .done
1351
1352 ;
1353 ; getfssec: Get multiple sectors from a file
1354 ;
1355 ;       Same as above, except SI is a pointer to a open_file_t
1356 ;
1357 ;       ES:BX   -> Buffer
1358 ;       DS:SI   -> Pointer to open_file_t
1359 ;       CX      -> Sector count (0FFFFh = until end of file)
1360 ;                  Must not exceed the ES segment
1361 ;       Returns CF=1 on EOF (not necessarily error)
1362 ;       All arguments are advanced to reflect data read.
1363 ;
1364 getfssec:
1365                 push edx
1366                 movzx edx,cx
1367                 cmp edx,[si+4]
1368                 jbe .sizeok
1369                 mov edx,[si+4]
1370                 mov cx,dx
1371 .sizeok:
1372                 sub [si+4],edx
1373                 mov edx,[si]
1374                 call getfssec_edx
1375                 mov [si],edx
1376                 pop edx
1377                 ret
1378
1379 ;
1380 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1381 ;              pointed at in the FAT tables.  CF=0 on return if end of file.
1382 ;
1383 nextcluster:
1384                 jmp strict short nextcluster_fat28      ; This gets patched
1385
1386 nextcluster_fat12:
1387                 push eax
1388                 push edx
1389                 push bx
1390                 push cx
1391                 push si
1392                 mov edx,edi
1393                 shr edi,1
1394                 pushf                   ; Save the shifted-out LSB (=CF)
1395                 add edx,edi
1396                 mov eax,edx
1397                 shr eax,9
1398                 call getfatsector
1399                 mov bx,dx
1400                 and bx,1FFh
1401                 mov cl,[gs:si+bx]
1402                 inc edx
1403                 mov eax,edx
1404                 shr eax,9
1405                 call getfatsector
1406                 mov bx,dx
1407                 and bx,1FFh
1408                 mov ch,[gs:si+bx]
1409                 popf
1410                 jnc .even
1411                 shr cx,4
1412 .even:          and cx,0FFFh
1413                 movzx edi,cx
1414                 cmp di,0FF0h
1415                 pop si
1416                 pop cx
1417                 pop bx
1418                 pop edx
1419                 pop eax
1420                 ret
1421
1422 ;
1423 ; FAT16 decoding routine.
1424 ;
1425 nextcluster_fat16:
1426                 push eax
1427                 push si
1428                 push bx
1429                 mov eax,edi
1430                 shr eax,SECTOR_SHIFT-1
1431                 call getfatsector
1432                 mov bx,di
1433                 add bx,bx
1434                 and bx,1FEh
1435                 movzx edi,word [gs:si+bx]
1436                 cmp di,0FFF0h
1437                 pop bx
1438                 pop si
1439                 pop eax
1440                 ret
1441 ;
1442 ; FAT28 ("FAT32") decoding routine.
1443 ;
1444 nextcluster_fat28:
1445                 push eax
1446                 push si
1447                 push bx
1448                 mov eax,edi
1449                 shr eax,SECTOR_SHIFT-2
1450                 call getfatsector
1451                 mov bx,di
1452                 add bx,bx
1453                 add bx,bx
1454                 and bx,1FCh
1455                 mov edi,dword [gs:si+bx]
1456                 and edi,0FFFFFFFh       ; 28 bits only
1457                 cmp edi,0FFFFFF0h
1458                 pop bx
1459                 pop si
1460                 pop eax
1461                 ret
1462
1463 ;
1464 ; nextsector:   Given a sector in EAX on input, return the next sector
1465 ;               of the same filesystem object, which may be the root
1466 ;               directory or a cluster chain.  Returns  EOF.
1467 ;
1468 ;               Assumes CS == DS.
1469 ;
1470 nextsector:
1471                 push edi
1472                 push edx
1473                 mov edx,[DataArea]
1474                 mov edi,eax
1475                 sub edi,edx
1476                 jae .isdata
1477
1478                 ; Root directory
1479                 inc eax
1480                 cmp eax,edx
1481                 cmc
1482                 jmp .done
1483
1484 .isdata:
1485                 not edi
1486                 test edi,[ClustMask]
1487                 jz .endcluster
1488
1489                 ; It's not the final sector in a cluster
1490                 inc eax
1491                 jmp .done
1492
1493 .endcluster:
1494                 push gs                 ; nextcluster trashes gs
1495                 push cx
1496                 not edi
1497                 mov cl,[ClustShift]
1498                 shr edi,cl
1499                 add edi,2
1500
1501                 ; Now EDI contains the cluster number
1502                 call nextcluster
1503                 cmc
1504                 jc .exit                ; There isn't anything else...
1505
1506                 ; New cluster number now in EDI
1507                 sub edi,2
1508                 shl edi,cl              ; CF <- 0, unless something is very wrong
1509                 lea eax,[edi+edx]
1510 .exit:
1511                 pop cx
1512                 pop gs
1513 .done:
1514                 pop edx
1515                 pop edi
1516                 ret
1517
1518 ;
1519 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1520 ;               and return a pointer in GS:SI, loading it if needed.
1521 ;
1522 ;               Assumes CS == DS.
1523 ;
1524 getfatsector:
1525                 add eax,[FAT]           ; FAT starting address
1526                 jmp getcachesector
1527
1528 ; -----------------------------------------------------------------------------
1529 ;  Common modules
1530 ; -----------------------------------------------------------------------------
1531
1532 %include "getc.inc"             ; getc et al
1533 %include "conio.inc"            ; Console I/O
1534 %include "plaincon.inc"         ; writechr
1535 %include "writestr.inc"         ; String output
1536 %include "configinit.inc"       ; Initialize configuration
1537 %include "parseconfig.inc"      ; High-level config file handling
1538 %include "parsecmd.inc"         ; Low-level config file handling
1539 %include "bcopy32.inc"          ; 32-bit bcopy
1540 %include "loadhigh.inc"         ; Load a file into high memory
1541 %include "font.inc"             ; VGA font stuff
1542 %include "graphics.inc"         ; VGA graphics
1543 %include "highmem.inc"          ; High memory sizing
1544 %include "strcpy.inc"           ; strcpy()
1545 %include "cache.inc"            ; Metadata disk cache
1546
1547 ; -----------------------------------------------------------------------------
1548 ;  Begin data section
1549 ; -----------------------------------------------------------------------------
1550
1551                 section .data
1552 copyright_str   db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1553                 db CR, LF, 0
1554 boot_prompt     db 'boot: ', 0
1555 wipe_char       db BS, ' ', BS, 0
1556 err_notfound    db 'Could not find kernel image: ',0
1557 err_notkernel   db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1558 err_noram       db 'It appears your computer has less than '
1559                 asciidec dosram_k
1560                 db 'K of low ("DOS")'
1561                 db CR, LF
1562                 db 'RAM.  Linux needs at least this amount to boot.  If you get'
1563                 db CR, LF
1564                 db 'this message in error, hold down the Ctrl key while'
1565                 db CR, LF
1566                 db 'booting, and I will take your word for it.', CR, LF, 0
1567 err_badcfg      db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1568 err_noparm      db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1569 err_noinitrd    db CR, LF, 'Could not find ramdisk image: ', 0
1570 err_nohighmem   db 'Not enough memory to load specified kernel.', CR, LF, 0
1571 err_highload    db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1572 err_oldkernel   db 'Cannot load a ramdisk with an old kernel image.'
1573                 db CR, LF, 0
1574 err_notdos      db ': attempted DOS system call', CR, LF, 0
1575 err_comlarge    db 'COMBOOT image too large.', CR, LF, 0
1576 err_a20         db CR, LF, 'A20 gate not responding!', CR, LF, 0
1577 err_bootfailed  db CR, LF, 'Boot failed: please change disks and press '
1578                 db 'a key to continue.', CR, LF, 0
1579 ready_msg       db 'Ready.', CR, LF, 0
1580 crlfloading_msg db CR, LF
1581 loading_msg     db 'Loading ', 0
1582 dotdot_msg      db '.'
1583 dot_msg         db '.', 0
1584 aborted_msg     db ' aborted.'                  ; Fall through to crlf_msg!
1585 crlf_msg        db CR, LF
1586 null_msg        db 0
1587 crff_msg        db CR, FF, 0
1588 syslinux_cfg1   db '/boot'                      ; /boot/syslinux/syslinux.cfg
1589 syslinux_cfg2   db '/syslinux'                  ; /syslinux/syslinux.cfg
1590 syslinux_cfg3   db '/'                          ; /syslinux.cfg
1591 ConfigName      db 'syslinux.cfg', 0            ; syslinux.cfg
1592
1593 ;
1594 ; Command line options we'd like to take a look at
1595 ;
1596 ; mem= and vga= are handled as normal 32-bit integer values
1597 initrd_cmd      db 'initrd='
1598 initrd_cmd_len  equ 7
1599
1600 ;
1601 ; Config file keyword table
1602 ;
1603 %include "keywords.inc"
1604
1605 ;
1606 ; Extensions to search for (in *forward* order).
1607 ;
1608 exten_table:    db 'CBT',0              ; COMBOOT (specific)
1609                 db 'BSS',0              ; Boot Sector (add superblock)
1610                 db 'BS ',0              ; Boot Sector
1611                 db 'COM',0              ; COMBOOT (same as DOS)
1612                 db 'C32',0              ; COM32
1613 exten_table_end:
1614                 dd 0, 0                 ; Need 8 null bytes here
1615
1616 ;
1617 ; Misc initialized (data) variables
1618 ;
1619 %ifdef debug                            ; This code for debugging only
1620 debug_magic     dw 0D00Dh               ; Debug code sentinel
1621 %endif
1622
1623                 alignb 4, db 0
1624 BufSafe         dw trackbufsize/SECTOR_SIZE     ; Clusters we can load into trackbuf
1625 BufSafeSec      dw trackbufsize/SECTOR_SIZE     ; = how many sectors?
1626 BufSafeBytes    dw trackbufsize         ; = how many bytes?
1627 EndOfGetCBuf    dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1628 %ifndef DEPEND
1629 %if ( trackbufsize % SECTOR_SIZE ) != 0
1630 %error trackbufsize must be a multiple of SECTOR_SIZE
1631 %endif
1632 %endif