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