1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
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.
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
14 ; Copyright (C) 1994-2007 H. Peter Anvin
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.
22 ; ****************************************************************************
30 ; Some semi-configurable constants... change on your own risk.
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
41 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
42 MAX_OPEN equ (1 << MAX_OPEN_LG2)
45 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
48 ; This is what we need to do when idle
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.
64 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
65 vk_rname: resb FILENAME_MAX ; Real name
68 vk_append: resb max_cmd_len+1 ; Command line
70 vk_end: equ $ ; Should be <= vk_size
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!!)
78 ; 0000h - main code/data segment (and BIOS segment)
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
87 ; File structure. This holds the information for each currently open file.
90 file_sector resd 1 ; Sector pointer (0 = structure free)
91 file_left resd 1 ; Number of sectors left
95 %if (open_file_t_size & (open_file_t_size-1))
96 %error "open_file_t is not a power of 2"
100 ; ---------------------------------------------------------------------------
102 ; ---------------------------------------------------------------------------
105 ; Memory below this point is reserved for the BIOS and the MBR
108 trackbufsize equ 8192
109 trackbuf resb trackbufsize ; Track buffer goes here
110 getcbuf resb trackbufsize
116 ; Expanded superblock
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
132 alignb open_file_t_size
133 Files resb MAX_OPEN*open_file_t_size
136 ; Constants for the xfer_buf_seg
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.
142 xbs_textbuf equ 0 ; Also hard-coded, do not change
143 xbs_vgabuf equ trackbufsize
144 xbs_vgatmpbuf equ 2*trackbufsize
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...
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
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.
164 jmp short start ; 2 bytes
167 ; "Superblock" follows -- it's in the boot sector, so it's already
168 ; loaded and ready for us
170 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
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.
177 bx %+ %1 equ SuperInfo+($-superblock)*8+4
182 bx %+ %1 equ SuperInfo+($-superblock)*8
187 bx %+ %1 equ $ ; no expansion for dwords
202 superinfo_size equ ($-superblock)-1 ; How much to expand
206 ; This is as far as FAT12/16 and FAT32 are consistent
208 zb 54 ; FAT12/16 need 26 more bytes,
209 ; FAT32 need 54 more bytes
210 superblock_len equ $-superblock
212 SecPerClust equ bxSecPerClust
214 ; Note we don't check the constraints above now; we did that at install
218 cli ; No interrupts yet, please
225 mov sp,StackBuf ; Just below BSS
228 ; DS:SI may contain a partition table entry. Preserve it for us.
230 mov cx,8 ; Save partition info
234 mov ds,ax ; Now we can initialize DS...
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?)
241 ; Of course, if BIOSes had been properly programmed, we wouldn't have
242 ; had to waste precious space with this code.
245 lfs si,[bx] ; FS:SI -> original fdctab
246 push fs ; Save on stack in case we need to bail
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
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
266 int 13h ; Some BIOSes need this
268 jmp short not_harddisk
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.
274 ; Would it be better to zero out bsHidden if we don't have a partition table?
276 ; Note: di points to beyond the end of PartInfo
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)
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.
290 ; DL == drive # still
297 inc dx ; Contains # of heads - 1
300 mov [bsSecPerTrack],cx
304 ; Ready to enable interrupts, captain
309 ; Do we have EBIOS (EDD)?
313 mov ah,41h ; EDD existence query
319 test cl,1 ; Extended disk access functionality set
322 ; We have EDD support...
324 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
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.
332 mov eax,[FirstSector] ; Sector start
333 mov bx,ldlinux_sys ; Where to load it
336 ; Some modicum of integrity checking
337 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
344 ; getonesec: get one disk sector
347 mov bp,1 ; One sector
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...)
357 ; On return, BX points to the first byte after the transferred
360 ; This routine assumes CS == DS, and trashes most registers.
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.
367 add eax,[bsHidden] ; Add partition offset
368 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
370 .jmp: jmp strict short getlinsec_cbios
375 ; getlinsec implementation for EBIOS (EDD)
379 push bp ; Sectors left
381 call maxtrans ; Enforce maximum transfer size
382 movzx edi,bp ; Sectors we are about to read
399 mov ah,42h ; Extended Read
403 lea sp,[si+16] ; Remove DAPA
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
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.
421 pushad ; Try resetting the device
426 loop .retry ; CX-- and jump if not zero
428 ;shr word [MaxTransfer],1 ; Reduce the transfer size
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
436 ; ... fall through ...
441 ; getlinsec implementation for legacy CBIOS
450 movzx esi,word [bsSecPerTrack]
451 movzx edi,word [bsHeads]
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.
458 xchg cx,dx ; CX <- sector index (0-based)
461 div edi ; Convert track to head/cyl
463 ; We should test this, but it doesn't fit...
468 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
469 ; BP = sectors to transfer, SI = bsSecPerTrack,
470 ; ES:BX = data target
473 call maxtrans ; Enforce maximum transfer size
475 ; Must not cross track boundaries, so BP <= SI-CX
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
490 xchg ax,bp ; Sector to transfer count
491 mov ah,02h ; Read sectors
499 movzx ecx,al ; ECX <- sectors transferred
500 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
515 xchg ax,bp ; Sectors transferred <- 0
516 shr word [MaxTransfer],1
518 ; Fall through to disk_error
521 ; kaboom: write a message and bail out.
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
533 ; Write error message, this assumes screen page 0
537 mov ah,0Eh ; Write to screen as TTY
538 mov bx,0007h ; Attribute
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
548 ; Truncate BP to MaxTransfer
557 ; Error message on failure
559 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
561 ; This fails if the boot sector overflows
564 FirstSector dd 0xDEADBEEF ; Location of sector 1
565 MaxTransfer dw 0x007F ; Max transfer size
566 bootsignature dw 0AA55h
569 ; ===========================================================================
571 ; ===========================================================================
572 ; Start of LDLINUX.SYS
573 ; ===========================================================================
577 syslinux_banner db 0Dh, 0Ah
583 db version_str, ' ', date, ' ', 0
584 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
587 ldlinux_magic dd LDLINUX_MAGIC
588 dd LDLINUX_MAGIC^HEXDATE
591 ; This area is patched by the installer. It is found by looking for
592 ; LDLINUX_MAGIC, plus 8 bytes.
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]
600 ; Space for up to 64 sectors, the theoretical maximum
601 SectorPtrs times 64 dd 0
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
615 ; Tell the user we got this far
617 mov si,syslinux_banner
621 ; Tell the user if we're using EBIOS or CBIOS
625 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
633 %define HAVE_BIOSNAME 1
638 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
639 ; sector again, though.
643 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
649 lodsd ; First sector of this chunk
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
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.
679 mov edx,-LDLINUX_MAGIC
685 and edx,edx ; Should be zero
686 jz all_read ; We're cool, go for it!
689 ; Uh-oh, something went bad...
691 mov si,checksumerr_msg
696 ; -----------------------------------------------------------------------------
697 ; Subroutines that have to be in the first sector
698 ; -----------------------------------------------------------------------------
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.
710 mov ah,0Eh ; Write to screen as TTY
711 mov bx,0007h ; Attribute
717 ; getlinsecsr: save registers, call getlinsec, restore registers
725 ; Checksum error message
727 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
732 cbios_name db 'CBIOS', 0
733 ebios_name db 'EBIOS', 0
740 cmp word [Debug_Magic],0D00Dh
745 rl_checkpt equ $ ; Must be <= 8000h
747 rl_checkpt_off equ ($-$$)
749 %if rl_checkpt_off > 400h
750 %error "Sector 1 overflow"
754 ; ----------------------------------------------------------------------------
755 ; End of code and data that have to be in the first sector
756 ; ----------------------------------------------------------------------------
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.
768 ; Insane hack to expand the superblock to dwords
774 mov cx,superinfo_size
778 stosd ; Store expanded word
780 stosd ; Store expanded byte
784 ; Compute some information about this filesystem.
787 ; First, generate the map of regions
792 mov edx,[bsHugeSectors]
794 mov [TotalSectors],edx
796 mov eax,[bxResSectors]
797 mov [FAT],eax ; Beginning of FAT
801 mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
805 mov [RootDirArea],eax ; Beginning of root directory
806 mov [RootDir],eax ; For FAT12/16 == root dir location
808 mov edx,[bxRootDirEnts]
809 add dx,SECTOR_SIZE/32-1
810 shr dx,SECTOR_SHIFT-5
811 mov [RootDirSize],edx
813 mov [DataArea],eax ; Beginning of data area
815 ; Next, generate a cluster size shift count and mask
816 mov eax,[bxSecPerClust]
821 mov [ClustByteShift],cl
830 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
833 mov eax,[TotalSectors]
835 shr eax,cl ; cl == ClustShift
836 mov cl,nextcluster_fat12-(nextcluster+2)
837 cmp eax,4085 ; FAT12 limit
839 mov cl,nextcluster_fat16-(nextcluster+2)
840 cmp eax,65525 ; FAT16 limit
843 ; FAT32, root directory is a cluster chain
846 mov eax,[bootsec+44] ; Root directory cluster
851 mov cl,nextcluster_fat28-(nextcluster+2)
853 mov byte [nextcluster+1],cl
856 ; Common initialization code
858 %include "cpuinit.inc"
862 ; Clear Files structures
865 mov cx,(MAX_OPEN*open_file_t_size)/4
870 ; Initialize the metadata cache
875 ; Now, everything is "up and running"... patch kaboom for more
876 ; verbosity and using the full screen system
879 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
882 ; Now we're all set to start with our *real* business. First load the
883 ; configuration file (if any) and parse it.
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...
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.
896 ; Load configuration file
908 mov eax,[PrevDir] ; Make the directory with syslinux.cfg ...
909 mov [CurrentDir],eax ; ... the current directory
912 ; Now we have the config file open. Parse the config file and
913 ; run the user interface.
918 ; Linux kernel loading code is common.
920 %include "runkernel.inc"
923 ; COMBOOT-loading code
925 %include "comboot.inc"
927 %include "cmdline.inc"
930 ; Boot sector loading code
932 %include "bootsect.inc"
940 ; allocate_file: Allocate a file structure
953 .check: cmp dword [bx], byte 0
955 add bx,open_file_t_size ; ZF = 0
957 ; ZF = 0 if we fell out of the loop
963 ; Search a specific directory for a pre-mangled filename in
964 ; MangledBuf, in the directory starting in sector EAX.
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
971 ; Assumes DS == ES == CS.
976 ; EAX = file length (MAY BE ZERO!)
977 ; DL = file attributes
994 ; EAX <- directory sector to scan
996 ; GS:SI now points to this sector
998 mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
1001 jz .failure ; Hit directory high water mark
1002 test byte [gs:si+11],8 ; Ignore volume labels and
1003 ; VFAT long filename entries
1020 jnc .scansector ; CF is set if we're at end
1022 ; If we get here, we failed
1029 xor eax,eax ; ZF <- 1
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
1038 mov dx,[gs:si+20] ; High cluster word
1040 mov dx,[gs:si+26] ; Low cluster word
1044 mov [bx],edx ; Starting sector
1046 mov eax,[gs:si+28] ; File length again
1047 mov dl,[gs:si+11] ; File attribute
1048 mov si,bx ; File pointer...
1067 ; DX:AX or EAX = file length in bytes
1071 ; Assumes CS == DS == ES, and trashes BX and CX.
1074 mov eax,[CurrentDir]
1075 cmp byte [di],'/' ; Root directory?
1082 push eax ; <A> Current directory sector
1092 pop eax ; <A> Current directory sector
1094 mov [PrevDir],eax ; Remember last directory searched
1097 call mangle_dos_name ; MangledBuf <- component
1100 jz .notfound ; Pathname component missing
1102 cmp byte [di-1],'/' ; Do we expect a directory
1105 ; Otherwise, it should be a file
1107 test dl,18h ; Subdirectory|Volume Label
1108 jnz .badfile ; If not a file, it's a bad thing
1110 ; SI and EAX are already set
1112 shr edx,16 ; Old 16-bit remnant...
1113 and eax,eax ; EAX != 0
1117 ; If we expected a directory, it better be one...
1119 test dl,10h ; Subdirectory
1123 xchg eax,[si+file_sector] ; Get sector number and free file structure
1124 jmp .pathwalk ; Walk the next bit of the path
1128 mov [si],eax ; Free file structure
1137 CurrentDir resd 1 ; Current directory
1138 PrevDir resd 1 ; Last scanned directory
1144 ; kaboom2: once everything is loaded, replace the part of kaboom
1145 ; starting with "kaboom.patch" with this part
1148 mov si,err_bootfailed
1152 int 19h ; And try once more to boot...
1153 .norge: jmp short .norge ; If int 19h returned; this is the end
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.
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.
1170 mov cx,FILENAME_MAX-1
1175 cmp al,' ' ; If control or space, end
1177 cmp al,'\' ; Backslash?
1179 mov al,'/' ; Change to forward slash
1181 cmp al,ah ; Repeated slash?
1188 .mn_skip: loop .mn_loop
1190 cmp bx,di ; At the beginning of the buffer?
1192 cmp byte [es:di-1],'.' ; Terminal dot?
1194 cmp byte [es:di-1],'/' ; Terminal slash?
1196 .mn_kill: dec di ; If so, remove it
1200 inc cx ; At least one null byte
1201 xor ax,ax ; Zero-fill name
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.
1213 ; DS:SI -> input mangled file name
1214 ; ES:DI -> output buffer
1216 ; On return, DI points to the first byte after the output name,
1217 ; which is set to a null byte.
1219 unmangle_name: call strcpy
1220 dec di ; Point to final null byte
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.
1234 mov cx,11 ; # of bytes to write
1237 cmp al,' ' ; If control or space, end
1239 cmp al,'/' ; Slash, too
1241 cmp al,'.' ; Period -> space-fill
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
1258 mov bx,ucase_tab-ucase_low
1261 loop .loop ; Don't continue if too long
1263 mov al,' ' ; Space-fill name
1264 rep stosb ; Doesn't do anything if CX=0
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 :-)
1277 ; The table only covers the range 129 to 164; the rest we can deal with.
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
1289 ; getfssec_edx: Get multiple sectors from a file
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
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.
1306 xor ebp,ebp ; Fragment sector count
1307 push edx ; Starting sector pointer
1315 add ax,bx ; Now AX = how far into 64K block we are
1316 not ax ; Bytes left in 64K block
1318 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
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
1325 cmp edx,eax ; Did it match?
1328 pop eax ; Starting sector pointer
1330 lea eax,[eax+ebp-1] ; This is the last sector actually read
1332 add bx,bp ; Adjust buffer pointer
1348 ; getfssec: Get multiple sectors from a file
1350 ; Same as above, except SI is a pointer to a open_file_t
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.
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.
1379 jmp strict short nextcluster_fat28 ; This gets patched
1389 pushf ; Save the shifted-out LSB (=CF)
1418 ; FAT16 decoding routine.
1425 shr eax,SECTOR_SHIFT-1
1430 movzx edi,word [gs:si+bx]
1437 ; FAT28 ("FAT32") decoding routine.
1444 shr eax,SECTOR_SHIFT-2
1450 mov edi,dword [gs:si+bx]
1451 and edi,0FFFFFFFh ; 28 bits only
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.
1481 test edi,[ClustMask]
1484 ; It's not the final sector in a cluster
1489 push gs ; nextcluster trashes gs
1496 ; Now EDI contains the cluster number
1499 jc .exit ; There isn't anything else...
1501 ; New cluster number now in EDI
1503 shl edi,cl ; CF <- 0, unless something is very wrong
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.
1520 add eax,[FAT] ; FAT starting address
1523 ; -----------------------------------------------------------------------------
1525 ; -----------------------------------------------------------------------------
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
1541 ; -----------------------------------------------------------------------------
1542 ; Begin data section
1543 ; -----------------------------------------------------------------------------
1546 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
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 '
1554 db 'K of low ("DOS")'
1556 db 'RAM. Linux needs at least this amount to boot. If you get'
1558 db 'this message in error, hold down the Ctrl key while'
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.'
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
1578 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
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
1588 ; Command line options we'd like to take a look at
1590 ; mem= and vga= are handled as normal 32-bit integer values
1591 initrd_cmd db 'initrd='
1592 initrd_cmd_len equ 7
1595 ; Config file keyword table
1597 %include "keywords.inc"
1600 ; Extensions to search for (in *forward* order).
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)
1608 dd 0, 0 ; Need 8 null bytes here
1611 ; Misc initialized (data) variables
1613 %ifdef debug ; This code for debugging only
1614 debug_magic dw 0D00Dh ; Debug code sentinel
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
1623 %if ( trackbufsize % SECTOR_SIZE ) != 0
1624 %error trackbufsize must be a multiple of SECTOR_SIZE