1 ; -*- fundamental -*- (asm-mode sucks)
3 ; ****************************************************************************
7 ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
8 ; functionality is good to have for installation floppies, where it may
9 ; be hard to find a functional Linux system to run LILO off.
11 ; This program allows manipulation of the disk to take place entirely
12 ; from MS-LOSS, and can be especially useful in conjunction with the
15 ; Copyright (C) 1994-2005 H. Peter Anvin
17 ; This program is free software; you can redistribute it and/or modify
18 ; it under the terms of the GNU General Public License as published by
19 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
20 ; Boston MA 02111-1307, USA; either version 2 of the License, or
21 ; (at your option) any later version; incorporated herein by reference.
23 ; ****************************************************************************
32 %include "tracers.inc"
35 ; Some semi-configurable constants... change on your own risk.
38 FILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null)
39 FILENAME_MAX equ 11 ; Max mangled filename size
40 NULLFILE equ ' ' ; First char space == null filename
41 NULLOFFSET equ 0 ; Position in which to look
42 retry_count equ 16 ; How patient are we with the disk?
43 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
44 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
46 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
47 MAX_OPEN equ (1 << MAX_OPEN_LG2)
50 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
53 ; This is what we need to do when idle
63 ; The following structure is used for "virtual kernels"; i.e. LILO-style
64 ; option labels. The options we permit here are `kernel' and `append
65 ; Since there is no room in the bottom 64K for all of these, we
66 ; stick them at vk_seg:0000 and copy them down before we need them.
69 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
70 vk_rname: resb FILENAME_MAX ; Real name
73 vk_append: resb max_cmd_len+1 ; Command line
75 vk_end: equ $ ; Should be <= vk_size
79 ; Segment assignments in the bottom 640K
80 ; Stick to the low 512K in case we're using something like M-systems flash
81 ; which load a driver into low RAM (evil!!)
83 ; 0000h - main code/data segment (and BIOS segment)
85 real_mode_seg equ 4000h
86 cache_seg equ 3000h ; 64K area for metadata cache
87 vk_seg equ 2000h ; Virtual kernels
88 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
89 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
92 ; File structure. This holds the information for each currently open file.
95 file_sector resd 1 ; Sector pointer (0 = structure free)
96 file_left resd 1 ; Number of sectors left
100 %if (open_file_t_size & (open_file_t_size-1))
101 %error "open_file_t is not a power of 2"
105 ; ---------------------------------------------------------------------------
107 ; ---------------------------------------------------------------------------
110 ; Memory below this point is reserved for the BIOS and the MBR
113 trackbufsize equ 8192
114 trackbuf resb trackbufsize ; Track buffer goes here
115 getcbuf resb trackbufsize
121 ; Expanded superblock
123 resq 16 ; The first 16 bytes expanded 8 times
124 FAT resd 1 ; Location of (first) FAT
125 RootDirArea resd 1 ; Location of root directory area
126 RootDir resd 1 ; Location of root directory proper
127 DataArea resd 1 ; Location of data area
128 RootDirSize resd 1 ; Root dir size in sectors
129 TotalSectors resd 1 ; Total number of sectors
130 EndSector resd 1 ; Location of filesystem end
131 ClustSize resd 1 ; Bytes/cluster
132 ClustMask resd 1 ; Sectors/cluster - 1
133 CopySuper resb 1 ; Distinguish .bs versus .bss
134 DriveNumber resb 1 ; BIOS drive number
135 ClustShift resb 1 ; Shift count for sectors/cluster
136 ClustByteShift resb 1 ; Shift count for bytes/cluster
138 alignb open_file_t_size
139 Files resb MAX_OPEN*open_file_t_size
142 ; Constants for the xfer_buf_seg
144 ; The xfer_buf_seg is also used to store message file buffers. We
145 ; need two trackbuffers (text and graphics), plus a work buffer
146 ; for the graphics decompressor.
148 xbs_textbuf equ 0 ; Also hard-coded, do not change
149 xbs_vgabuf equ trackbufsize
150 xbs_vgatmpbuf equ 2*trackbufsize
155 ; Some of the things that have to be saved very early are saved
156 ; "close" to the initial stack pointer offset, in order to
157 ; reduce the code size...
159 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
160 PartInfo equ StackBuf ; Saved partition table entry
161 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
162 OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
165 ; Primary entry point. Tempting as though it may be, we can't put the
166 ; initial "cli" here; the jmp opcode in the first byte is part of the
167 ; "magic number" (using the term very loosely) for the DOS superblock.
170 jmp short start ; 2 bytes
173 ; "Superblock" follows -- it's in the boot sector, so it's already
174 ; loaded and ready for us
176 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
178 ; These are the fields we actually care about. We end up expanding them
179 ; all to dword size early in the code, so generate labels for both
180 ; the expanded and unexpanded versions.
183 bx %+ %1 equ SuperInfo+($-superblock)*8+4
188 bx %+ %1 equ SuperInfo+($-superblock)*8
193 bx %+ %1 equ $ ; no expansion for dwords
208 superinfo_size equ ($-superblock)-1 ; How much to expand
212 ; This is as far as FAT12/16 and FAT32 are consistent
214 zb 54 ; FAT12/16 need 26 more bytes,
215 ; FAT32 need 54 more bytes
216 superblock_len equ $-superblock
218 SecPerClust equ bxSecPerClust
220 ; Note we don't check the constraints above now; we did that at install
224 cli ; No interrupts yet, please
231 mov sp,StackBuf ; Just below BSS
234 ; DS:SI may contain a partition table entry. Preserve it for us.
236 mov cx,8 ; Save partition info
240 mov ds,ax ; Now we can initialize DS...
243 ; Now sautee the BIOS floppy info block to that it will support decent-
244 ; size transfers; the floppy block is 11 bytes and is stored in the
245 ; INT 1Eh vector (brilliant waste of resources, eh?)
247 ; Of course, if BIOSes had been properly programmed, we wouldn't have
248 ; had to waste precious space with this code.
251 lfs si,[bx] ; FS:SI -> original fdctab
252 push fs ; Save on stack in case we need to bail
255 ; Save the old fdctab even if hard disk so the stack layout
256 ; is the same. The instructions above do not change the flags
257 mov [DriveNumber],dl ; Save drive number in DL
258 and dl,dl ; If floppy disk (00-7F), assume no
263 mov cl,6 ; 12 bytes (CX == 0)
264 ; es:di -> FloppyTable already
265 ; This should be safe to do now, interrupts are off...
266 mov [bx],di ; FloppyTable
267 mov [bx+2],ax ; Segment 0
268 fs rep movsw ; Faster to move words
269 mov cl,[bsSecPerTrack] ; Patch the sector count
272 int 13h ; Some BIOSes need this
274 jmp short not_harddisk
276 ; The drive number and possibly partition information was passed to us
277 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
278 ; trust that rather than what the superblock contains.
280 ; Would it be better to zero out bsHidden if we don't have a partition table?
282 ; Note: di points to beyond the end of PartInfo
285 test byte [di-16],7Fh ; Sanity check: "active flag" should
286 jnz no_partition ; be 00 or 80
287 mov eax,[di-8] ; Partition offset (dword)
291 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
292 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
293 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
294 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
296 ; DL == drive # still
303 inc dx ; Contains # of heads - 1
306 mov [bsSecPerTrack],cx
310 ; Ready to enable interrupts, captain
315 ; Do we have EBIOS (EDD)?
319 mov ah,41h ; EDD existence query
325 test cl,1 ; Extended disk access functionality set
328 ; We have EDD support...
330 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
334 ; Load the first sector of LDLINUX.SYS; this used to be all proper
335 ; with parsing the superblock and root directory; it doesn't fit
336 ; together with EBIOS support, unfortunately.
338 mov eax,[FirstSector] ; Sector start
339 mov bx,ldlinux_sys ; Where to load it
342 ; Some modicum of integrity checking
343 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
350 ; getonesec: get one disk sector
353 mov bp,1 ; One sector
357 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
358 ; number in EAX into the buffer at ES:BX. We try to optimize
359 ; by loading up to a whole track at a time, but the user
360 ; is responsible for not crossing a 64K boundary.
361 ; (Yes, BP is weird for a count, but it was available...)
363 ; On return, BX points to the first byte after the transferred
366 ; This routine assumes CS == DS, and trashes most registers.
368 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
369 ; that is dead from that point; this saves space. However, please keep
370 ; the order to dst,src to keep things sane.
373 add eax,[bsHidden] ; Add partition offset
374 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
376 .jmp: jmp strict short getlinsec_cbios
381 ; getlinsec implementation for EBIOS (EDD)
385 push bp ; Sectors left
387 call maxtrans ; Enforce maximum transfer size
388 movzx edi,bp ; Sectors we are about to read
401 mov ah,42h ; Extended Read
409 lea sp,[si+16] ; Remove DAPA
412 add eax,edi ; Advance sector pointer
413 sub bp,di ; Sectors left
414 shl di,SECTOR_SHIFT ; 512-byte sectors
415 add bx,di ; Advance buffer pointer
422 ; Some systems seem to get "stuck" in an error state when
423 ; using EBIOS. Doesn't happen when using CBIOS, which is
424 ; good, since some other systems get timeout failures
425 ; waiting for the floppy disk to spin up.
427 pushad ; Try resetting the device
431 loop .retry ; CX-- and jump if not zero
433 shr word [MaxTransfer],1 ; Reduce the transfer size
436 ; Total failure. Try falling back to CBIOS.
437 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
438 mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
441 ; ... fall through ...
446 ; getlinsec implementation for legacy CBIOS
455 movzx esi,word [bsSecPerTrack]
456 movzx edi,word [bsHeads]
458 ; Dividing by sectors to get (track,sector): we may have
459 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
463 xchg cx,dx ; CX <- sector index (0-based)
466 div edi ; Convert track to head/cyl
468 ; We should test this, but it doesn't fit...
473 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
474 ; BP = sectors to transfer, SI = bsSecPerTrack,
475 ; ES:BX = data target
478 call maxtrans ; Enforce maximum transfer size
480 ; Must not cross track boundaries, so BP <= SI-CX
487 shl ah,6 ; Because IBM was STOOPID
488 ; and thought 8 bits were enough
489 ; then thought 10 bits were enough...
490 inc cx ; Sector numbers are 1-based, sigh
495 xchg ax,bp ; Sector to transfer count
496 mov ah,02h ; Read sectors
504 movzx ecx,al ; ECX <- sectors transferred
505 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
520 xchg ax,bp ; Sectors transferred <- 0
521 shr word [MaxTransfer],1
523 ; Fall through to disk_error
526 ; kaboom: write a message and bail out.
532 mov sp,StackBuf-4 ; Reset stack
533 mov ds,si ; Reset data segment
534 pop dword [fdctab] ; Restore FDC table
535 .patch: ; When we have full code, intercept here
538 ; Write error message, this assumes screen page 0
542 mov ah,0Eh ; Write to screen as TTY
543 mov bx,0007h ; Attribute
548 int 16h ; Wait for keypress
549 int 19h ; And try once more to boot...
550 .norge: jmp short .norge ; If int 19h returned; this is the end
553 ; Truncate BP to MaxTransfer
562 ; Error message on failure
564 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
566 ; This fails if the boot sector overflows
569 FirstSector dd 0xDEADBEEF ; Location of sector 1
570 MaxTransfer dw 0x007F ; Max transfer size
571 bootsignature dw 0AA55h
574 ; ===========================================================================
576 ; ===========================================================================
577 ; Start of LDLINUX.SYS
578 ; ===========================================================================
582 syslinux_banner db 0Dh, 0Ah
588 db version_str, ' ', date, ' ', 0
589 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
592 ldlinux_magic dd LDLINUX_MAGIC
593 dd LDLINUX_MAGIC^HEXDATE
596 ; This area is patched by the installer. It is found by looking for
597 ; LDLINUX_MAGIC, plus 8 bytes.
600 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
601 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
602 CheckSum dd 0 ; Checksum starting at ldlinux_sys
603 ; value = LDLINUX_MAGIC - [sum of dwords]
605 ; Space for up to 64 sectors, the theoretical maximum
606 SectorPtrs times 64 dd 0
610 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
611 ; instead of 0000:7C00 and the like. We don't want to add anything
612 ; more to the boot sector, so it is written to not assume a fixed
613 ; value in CS, but we don't want to deal with that anymore from now
620 ; Tell the user we got this far
622 mov si,syslinux_banner
626 ; Tell the user if we're using EBIOS or CBIOS
630 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
637 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
638 ; sector again, though.
642 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
648 lodsd ; First sector of this chunk
656 inc edx ; Next linear sector
657 cmp [esi],edx ; Does it match
658 jnz .chunk_ready ; If not, this is it
659 add esi,4 ; If so, add sector to chunk
660 jmp short .make_chunk
671 ; All loaded up, verify that we got what we needed.
672 ; Note: the checksum field is embedded in the checksum region, so
673 ; by the time we get to the end it should all cancel out.
678 mov edx,-LDLINUX_MAGIC
684 and edx,edx ; Should be zero
685 jz all_read ; We're cool, go for it!
688 ; Uh-oh, something went bad...
690 mov si,checksumerr_msg
695 ; -----------------------------------------------------------------------------
696 ; Subroutines that have to be in the first sector
697 ; -----------------------------------------------------------------------------
701 ; writestr: write a null-terminated string to the console
702 ; This assumes we're on page 0. This is only used for early
703 ; messages, so it should be OK.
709 mov ah,0Eh ; Write to screen as TTY
710 mov bx,0007h ; Attribute
716 ; getlinsecsr: save registers, call getlinsec, restore registers
724 ; Checksum error message
726 checksumerr_msg db 'Load error - ', 0 ; Boot failed appended
731 bios_name db 'CBIOS', 0
738 cmp word [Debug_Magic],0D00Dh
743 rl_checkpt equ $ ; Must be <= 8000h
745 rl_checkpt_off equ ($-$$)
747 %if rl_checkpt_off > 400h
748 %error "Sector 1 overflow"
752 ; ----------------------------------------------------------------------------
753 ; End of code and data that have to be in the first sector
754 ; ----------------------------------------------------------------------------
758 ; Let the user (and programmer!) know we got this far. This used to be
759 ; in Sector 1, but makes a lot more sense here.
766 ; Insane hack to expand the superblock to dwords
772 mov cx,superinfo_size
776 stosd ; Store expanded word
778 stosd ; Store expanded byte
782 ; Compute some information about this filesystem.
785 ; First, generate the map of regions
790 mov edx,[bsHugeSectors]
792 mov [TotalSectors],edx
797 mov eax,[bxResSectors]
798 mov [FAT],eax ; Beginning of FAT
802 mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
806 mov [RootDirArea],eax ; Beginning of root directory
807 mov [RootDir],eax ; For FAT12/16 == root dir location
809 mov edx,[bxRootDirEnts]
810 add dx,SECTOR_SIZE/32-1
811 shr dx,SECTOR_SHIFT-5
812 mov [RootDirSize],edx
814 mov [DataArea],eax ; Beginning of data area
816 ; Next, generate a cluster size shift count and mask
817 mov eax,[bxSecPerClust]
822 mov [ClustByteShift],cl
831 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
836 shr eax,cl ; cl == ClustShift
837 mov cl,nextcluster_fat12-(nextcluster+2)
838 cmp eax,4085 ; FAT12 limit
840 mov cl,nextcluster_fat16-(nextcluster+2)
841 cmp eax,65525 ; FAT16 limit
844 ; FAT32, root directory is a cluster chain
847 mov eax,[bootsec+44] ; Root directory cluster
852 mov cl,nextcluster_fat28-(nextcluster+2)
854 mov byte [nextcluster+1],cl
857 ; Common initialization code
859 %include "cpuinit.inc"
863 ; Clear Files structures
866 mov cx,(MAX_OPEN*open_file_t_size)/4
871 ; Initialize the metadata cache
876 ; Now, everything is "up and running"... patch kaboom for more
877 ; verbosity and using the full screen system
880 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
883 ; Now we're all set to start with our *real* business. First load the
884 ; configuration file (if any) and parse it.
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...
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.
897 ; Load configuration file
904 ; Now we have the config file open. Parse the config file and
905 ; run the user interface.
910 ; Linux kernel loading code is common.
912 %include "runkernel.inc"
915 ; COMBOOT-loading code
917 %include "comboot.inc"
919 %include "cmdline.inc"
922 ; Boot sector loading code
924 %include "bootsect.inc"
927 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
938 ac_kill: mov si,aborted_msg
941 ; abort_load: Called by various routines which wants to print a fatal
942 ; error message and return to the command prompt. Since this
943 ; may happen at just about any stage of the boot process, assume
944 ; our state is messed up, and just reset the segment registers
945 ; and the stack forcibly.
947 ; SI = offset (in _text) of error message to print
950 mov ax,cs ; Restore CS = DS = ES
954 mov sp,StackBuf-2*3 ; Reset stack
955 mov ss,ax ; Just in case...
957 call cwritestr ; Expects SI -> error msg
958 al_ok: jmp enter_command ; Return to command prompt
966 ; allocate_file: Allocate a file structure
979 .check: cmp dword [bx], byte 0
981 add bx,open_file_t_size ; ZF = 0
983 ; ZF = 0 if we fell out of the loop
989 ; Search the root directory for a pre-mangled filename in DS:DI.
991 ; NOTE: This file considers finding a zero-length file an
992 ; error. This is so we don't have to deal with that special
993 ; case elsewhere in the program (most loops have the test
999 ; DX:AX = file length in bytes
1013 mov eax,[RootDir] ; First root directory sector
1017 ; GS:SI now points to this sector
1019 mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
1022 jz .failure ; Hit directory high water mark
1036 jnc .scansector ; CF is set if we're at end
1038 ; If we get here, we failed
1046 mov eax,[gs:si+28] ; File size
1047 add eax,SECTOR_SIZE-1
1048 shr eax,SECTOR_SHIFT
1049 jz .failure ; Zero-length file
1053 mov dx,[gs:si+20] ; High cluster word
1055 mov dx,[gs:si+26] ; Low cluster word
1059 mov [bx],edx ; Starting sector
1061 mov eax,[gs:si+28] ; File length again
1062 mov dx,[gs:si+30] ; 16-bitism, sigh
1064 and eax,eax ; ZF <- 0
1071 ; writechr: Write a single character in AL to the console without
1072 ; mangling any registers; handle video pages correctly.
1075 call write_serial ; write to serial port if needed
1077 test byte [cs:DisplayCon], 01h
1081 mov bl,07h ; attribute
1082 mov bh,[cs:BIOS_page] ; current page
1091 ; kaboom2: once everything is loaded, replace the part of kaboom
1092 ; starting with "kaboom.patch" with this part
1095 mov si,err_bootfailed
1099 int 19h ; And try once more to boot...
1100 .norge: jmp short .norge ; If int 19h returned; this is the end
1103 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
1104 ; to by ES:DI; ends on encountering any whitespace
1108 mov cx,11 ; # of bytes to write
1111 cmp al,' ' ; If control or space, end
1113 cmp al,'.' ; Period -> space-fill
1120 jmp short mn_not_lower
1121 mn_is_period: mov al,' ' ; We need to space-fill
1122 mn_period_loop: cmp cx,3 ; If <= 3 characters left
1123 jbe mn_loop ; Just ignore it
1124 stosb ; Otherwise, write a period
1125 loop mn_period_loop ; Dec CX and (always) jump
1126 mn_not_uslower: cmp al,ucase_low
1130 mov bx,ucase_tab-ucase_low
1133 loop mn_loop ; Don't continue if too long
1135 mov al,' ' ; Space-fill name
1136 rep stosb ; Doesn't do anything if CX=0
1140 ; Upper-case table for extended characters; this is technically code page 865,
1141 ; but code page 437 users will probably not miss not being able to use the
1142 ; cent sign in kernel images too much :-)
1144 ; The table only covers the range 129 to 164; the rest we can deal with.
1148 ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1149 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1150 db 157, 156, 157, 158, 159, 'AIOU', 165
1153 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1154 ; filename to the conventional representation. This is needed
1155 ; for the BOOT_IMAGE= parameter for the kernel.
1156 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1157 ; known to be shorter.
1159 ; DS:SI -> input mangled file name
1160 ; ES:DI -> output buffer
1162 ; On return, DI points to the first byte after the output name,
1163 ; which is set to a null byte.
1166 push si ; Save pointer to original name
1174 mov bp,di ; Position of last nonblank+1
1175 un_cb_space: loop un_copy_body
1177 mov al,'.' ; Don't save
1186 un_ce_space: loop un_copy_ext
1193 ; lower_case: Lower case a character in AL
1202 lc_1: cmp al,lcase_low
1207 mov bx,lcase_tab-lcase_low
1213 ; getfssec_edx: Get multiple sectors from a file
1215 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1216 ; and will correct the situation if it does, UNLESS *sectors* cross
1220 ; EDX -> Current sector number
1221 ; CX -> Sector count (0FFFFh = until end of file)
1222 ; Must not exceed the ES segment
1223 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1224 ; All arguments are advanced to reflect data read.
1230 xor ebp,ebp ; Fragment sector count
1231 push edx ; Starting sector pointer
1239 add ax,bx ; Now AX = how far into 64K block we are
1240 not ax ; Bytes left in 64K block
1242 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1244 jnb .do_read ; Unless there is at least 1 more sector room...
1245 mov eax,edx ; Current sector
1246 inc edx ; Predict it's the linearly next sector
1249 cmp edx,eax ; Did it match?
1252 pop eax ; Starting sector pointer
1254 lea eax,[eax+ebp-1] ; This is the last sector actually read
1256 add bx,bp ; Adjust buffer pointer
1272 ; getfssec: Get multiple sectors from a file
1274 ; Same as above, except SI is a pointer to a open_file_t
1277 ; DS:SI -> Pointer to open_file_t
1278 ; CX -> Sector count (0FFFFh = until end of file)
1279 ; Must not exceed the ES segment
1280 ; Returns CF=1 on EOF (not necessarily error)
1281 ; All arguments are advanced to reflect data read.
1299 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1300 ; pointed at in the FAT tables. CF=0 on return if end of file.
1303 jmp strict short nextcluster_fat28 ; This gets patched
1313 pushf ; Save the shifted-out LSB (=CF)
1342 ; FAT16 decoding routine.
1349 shr eax,SECTOR_SHIFT-1
1354 movzx edi,word [gs:si+bx]
1361 ; FAT28 ("FAT32") decoding routine.
1368 shr eax,SECTOR_SHIFT-2
1374 mov edi,dword [gs:si+bx]
1375 and edi,0FFFFFFFh ; 28 bits only
1383 ; nextsector: Given a sector in EAX on input, return the next sector
1384 ; of the same filesystem object, which may be the root
1385 ; directory or a cluster chain. Returns EOF.
1405 test edi,[ClustMask]
1408 ; It's not the final sector in a cluster
1413 push gs ; nextcluster trashes gs
1420 ; Now EDI contains the cluster number
1423 jc .exit ; There isn't anything else...
1425 ; New cluster number now in EDI
1427 shl edi,cl ; CF <- 0, unless something is very wrong
1438 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1439 ; and return a pointer in GS:SI, loading it if needed.
1444 add eax,[FAT] ; FAT starting address
1447 ; -----------------------------------------------------------------------------
1449 ; -----------------------------------------------------------------------------
1451 %include "getc.inc" ; getc et al
1452 %include "conio.inc" ; Console I/O
1453 %include "writestr.inc" ; String output
1454 %include "parseconfig.inc" ; High-level config file handling
1455 %include "parsecmd.inc" ; Low-level config file handling
1456 %include "bcopy32.inc" ; 32-bit bcopy
1457 %include "loadhigh.inc" ; Load a file into high memory
1458 %include "font.inc" ; VGA font stuff
1459 %include "graphics.inc" ; VGA graphics
1460 %include "highmem.inc" ; High memory sizing
1461 %include "strcpy.inc" ; strcpy()
1462 %include "cache.inc" ; Metadata disk cache
1464 ; -----------------------------------------------------------------------------
1465 ; Begin data section
1466 ; -----------------------------------------------------------------------------
1470 ; Lower-case table for codepage 865
1474 lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
1475 db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
1476 db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
1477 db 161, 162, 163, 164, 164
1479 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1481 boot_prompt db 'boot: ', 0
1482 wipe_char db BS, ' ', BS, 0
1483 err_notfound db 'Could not find kernel image: ',0
1484 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1485 err_noram db 'It appears your computer has less than '
1487 db 'K of low ("DOS")'
1489 db 'RAM. Linux needs at least this amount to boot. If you get'
1491 db 'this message in error, hold down the Ctrl key while'
1493 db 'booting, and I will take your word for it.', CR, LF, 0
1494 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1495 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1496 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1497 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1498 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1499 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1501 err_notdos db ': attempted DOS system call', CR, LF, 0
1502 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1503 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1504 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1505 db 'a key to continue.', CR, LF, 0
1506 ready_msg db 'Ready.', CR, LF, 0
1507 crlfloading_msg db CR, LF
1508 loading_msg db 'Loading ', 0
1511 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1514 crff_msg db CR, FF, 0
1515 syslinux_cfg db 'SYSLINUXCFG' ; Mangled form
1516 ConfigName db 'syslinux.cfg',0 ; Unmangled form
1518 manifest db 'MANIFEST '
1521 ; Command line options we'd like to take a look at
1523 ; mem= and vga= are handled as normal 32-bit integer values
1524 initrd_cmd db 'initrd='
1525 initrd_cmd_len equ 7
1528 ; Config file keyword table
1530 %include "keywords.inc"
1533 ; Extensions to search for (in *forward* order).
1535 exten_table: db 'CBT',0 ; COMBOOT (specific)
1536 db 'BSS',0 ; Boot Sector (add superblock)
1537 db 'BS ',0 ; Boot Sector
1538 db 'COM',0 ; COMBOOT (same as DOS)
1541 dd 0, 0 ; Need 8 null bytes here
1544 ; Misc initialized (data) variables
1546 %ifdef debug ; This code for debugging only
1547 debug_magic dw 0D00Dh ; Debug code sentinel
1551 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1552 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1553 BufSafeBytes dw trackbufsize ; = how many bytes?
1554 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1556 %if ( trackbufsize % SECTOR_SIZE ) != 0
1557 %error trackbufsize must be a multiple of SECTOR_SIZE