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