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