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 1994-2008 H. Peter Anvin - All Rights Reserved
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
67 vk_type: resb 1 ; Type of file
69 vk_append: resb max_cmd_len+1 ; Command line
71 vk_end: equ $ ; Should be <= vk_size
75 ; Segment assignments in the bottom 640K
76 ; Stick to the low 512K in case we're using something like M-systems flash
77 ; which load a driver into low RAM (evil!!)
79 ; 0000h - main code/data segment (and BIOS segment)
81 real_mode_seg equ 4000h
82 cache_seg equ 3000h ; 64K area for metadata cache
83 vk_seg equ 2000h ; Virtual kernels
84 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
85 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
88 ; File structure. This holds the information for each currently open file.
91 file_sector resd 1 ; Sector pointer (0 = structure free)
92 file_left resd 1 ; Number of sectors left
96 %if (open_file_t_size & (open_file_t_size-1))
97 %error "open_file_t is not a power of 2"
101 ; ---------------------------------------------------------------------------
103 ; ---------------------------------------------------------------------------
106 ; Memory below this point is reserved for the BIOS and the MBR
109 trackbufsize equ 8192
110 trackbuf resb trackbufsize ; Track buffer goes here
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-8 ; The 2nd high dword on the stack
157 OrigESDI equ StackBuf-4 ; The high dword on the stack
160 ; Primary entry point. Tempting as though it may be, we can't put the
161 ; initial "cli" here; the jmp opcode in the first byte is part of the
162 ; "magic number" (using the term very loosely) for the DOS superblock.
165 jmp short start ; 2 bytes
168 ; "Superblock" follows -- it's in the boot sector, so it's already
169 ; loaded and ready for us
171 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
173 ; These are the fields we actually care about. We end up expanding them
174 ; all to dword size early in the code, so generate labels for both
175 ; the expanded and unexpanded versions.
178 bx %+ %1 equ SuperInfo+($-superblock)*8+4
183 bx %+ %1 equ SuperInfo+($-superblock)*8
188 bx %+ %1 equ $ ; no expansion for dwords
203 superinfo_size equ ($-superblock)-1 ; How much to expand
207 ; This is as far as FAT12/16 and FAT32 are consistent
209 zb 54 ; FAT12/16 need 26 more bytes,
210 ; FAT32 need 54 more bytes
211 superblock_len equ $-superblock
213 SecPerClust equ bxSecPerClust
215 ; Note we don't check the constraints above now; we did that at install
219 cli ; No interrupts yet, please
226 mov sp,StackBuf ; Just below BSS
227 push es ; Save initial ES:DI -> $PnP pointer
231 ; DS:SI may contain a partition table entry. Preserve it for us.
233 mov cx,8 ; Save partition info
237 mov ds,ax ; Now we can initialize DS...
240 ; Now sautee the BIOS floppy info block to that it will support decent-
241 ; size transfers; the floppy block is 11 bytes and is stored in the
242 ; INT 1Eh vector (brilliant waste of resources, eh?)
244 ; Of course, if BIOSes had been properly programmed, we wouldn't have
245 ; had to waste precious space with this code.
248 lfs si,[bx] ; FS:SI -> original fdctab
249 push fs ; Save on stack in case we need to bail
252 ; Save the old fdctab even if hard disk so the stack layout
253 ; is the same. The instructions above do not change the flags
254 mov [DriveNumber],dl ; Save drive number in DL
255 and dl,dl ; If floppy disk (00-7F), assume no
260 mov cl,6 ; 12 bytes (CX == 0)
261 ; es:di -> FloppyTable already
262 ; This should be safe to do now, interrupts are off...
263 mov [bx],di ; FloppyTable
264 mov [bx+2],ax ; Segment 0
265 fs rep movsw ; Faster to move words
266 mov cl,[bsSecPerTrack] ; Patch the sector count
269 int 13h ; Some BIOSes need this
271 jmp short not_harddisk
273 ; The drive number and possibly partition information was passed to us
274 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
275 ; trust that rather than what the superblock contains.
277 ; Would it be better to zero out bsHidden if we don't have a partition table?
279 ; Note: di points to beyond the end of PartInfo
282 test byte [di-16],7Fh ; Sanity check: "active flag" should
283 jnz no_partition ; be 00 or 80
284 mov eax,[di-8] ; Partition offset (dword)
288 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
289 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
290 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
291 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
293 ; DL == drive # still
300 inc dx ; Contains # of heads - 1
303 mov [bsSecPerTrack],cx
307 ; Ready to enable interrupts, captain
312 ; Do we have EBIOS (EDD)?
316 mov ah,41h ; EDD existence query
322 test cl,1 ; Extended disk access functionality set
325 ; We have EDD support...
327 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
331 ; Load the first sector of LDLINUX.SYS; this used to be all proper
332 ; with parsing the superblock and root directory; it doesn't fit
333 ; together with EBIOS support, unfortunately.
335 mov eax,[FirstSector] ; Sector start
336 mov bx,ldlinux_sys ; Where to load it
339 ; Some modicum of integrity checking
340 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
347 ; getonesec: get one disk sector
350 mov bp,1 ; One sector
354 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
355 ; number in EAX into the buffer at ES:BX. We try to optimize
356 ; by loading up to a whole track at a time, but the user
357 ; is responsible for not crossing a 64K boundary.
358 ; (Yes, BP is weird for a count, but it was available...)
360 ; On return, BX points to the first byte after the transferred
363 ; This routine assumes CS == DS, and trashes most registers.
365 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
366 ; that is dead from that point; this saves space. However, please keep
367 ; the order to dst,src to keep things sane.
370 add eax,[bsHidden] ; Add partition offset
371 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
373 .jmp: jmp strict short getlinsec_cbios
378 ; getlinsec implementation for EBIOS (EDD)
382 push bp ; Sectors left
384 call maxtrans ; Enforce maximum transfer size
385 movzx edi,bp ; Sectors we are about to read
402 mov ah,42h ; Extended Read
406 lea sp,[si+16] ; Remove DAPA
409 add eax,edi ; Advance sector pointer
410 sub bp,di ; Sectors left
411 shl di,SECTOR_SHIFT ; 512-byte sectors
412 add bx,di ; Advance buffer pointer
419 ; Some systems seem to get "stuck" in an error state when
420 ; using EBIOS. Doesn't happen when using CBIOS, which is
421 ; good, since some other systems get timeout failures
422 ; waiting for the floppy disk to spin up.
424 pushad ; Try resetting the device
429 loop .retry ; CX-- and jump if not zero
431 ;shr word [MaxTransfer],1 ; Reduce the transfer size
434 ; Total failure. Try falling back to CBIOS.
435 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
436 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
439 ; ... fall through ...
444 ; getlinsec implementation for legacy CBIOS
453 movzx esi,word [bsSecPerTrack]
454 movzx edi,word [bsHeads]
456 ; Dividing by sectors to get (track,sector): we may have
457 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
461 xchg cx,dx ; CX <- sector index (0-based)
464 div edi ; Convert track to head/cyl
466 ; We should test this, but it doesn't fit...
471 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
472 ; BP = sectors to transfer, SI = bsSecPerTrack,
473 ; ES:BX = data target
476 call maxtrans ; Enforce maximum transfer size
478 ; Must not cross track boundaries, so BP <= SI-CX
485 shl ah,6 ; Because IBM was STOOPID
486 ; and thought 8 bits were enough
487 ; then thought 10 bits were enough...
488 inc cx ; Sector numbers are 1-based, sigh
493 xchg ax,bp ; Sector to transfer count
494 mov ah,02h ; Read sectors
502 movzx ecx,al ; ECX <- sectors transferred
503 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
518 xchg ax,bp ; Sectors transferred <- 0
519 shr word [MaxTransfer],1
521 ; Fall through to disk_error
524 ; kaboom: write a message and bail out.
530 mov sp,StackBuf-4 ; Reset stack
531 mov ds,si ; Reset data segment
532 pop dword [fdctab] ; Restore FDC table
533 .patch: ; When we have full code, intercept here
536 ; Write error message, this assumes screen page 0
540 mov ah,0Eh ; Write to screen as TTY
541 mov bx,0007h ; Attribute
546 .again: int 16h ; Wait for keypress
547 ; NB: replaced by int 18h if
548 ; chosen at install time..
549 int 19h ; And try once more to boot...
550 .norge: jmp short .norge ; If int 19h returned; this is the end
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
572 ; This field will be filled in 0xAA55 by the installer, but we abuse it
573 ; to house a pointer to the INT 16h instruction at
574 ; kaboom.again, which gets patched to INT 18h in RAID mode.
575 bootsignature dw kaboom.again-bootsec
578 ; ===========================================================================
580 ; ===========================================================================
581 ; Start of LDLINUX.SYS
582 ; ===========================================================================
586 syslinux_banner db 0Dh, 0Ah
592 db version_str, ' ', date, ' ', 0
593 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
596 ldlinux_magic dd LDLINUX_MAGIC
597 dd LDLINUX_MAGIC^HEXDATE
600 ; This area is patched by the installer. It is found by looking for
601 ; LDLINUX_MAGIC, plus 8 bytes.
604 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
605 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
606 CheckSum dd 0 ; Checksum starting at ldlinux_sys
607 ; value = LDLINUX_MAGIC - [sum of dwords]
609 ; Space for up to 64 sectors, the theoretical maximum
610 SectorPtrs times 64 dd 0
614 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
615 ; instead of 0000:7C00 and the like. We don't want to add anything
616 ; more to the boot sector, so it is written to not assume a fixed
617 ; value in CS, but we don't want to deal with that anymore from now
624 ; Tell the user we got this far
626 mov si,syslinux_banner
630 ; Tell the user if we're using EBIOS or CBIOS
634 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
642 %define HAVE_BIOSNAME 1
647 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
648 ; sector again, though.
652 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
658 lodsd ; First sector of this chunk
666 inc edx ; Next linear sector
667 cmp [si],edx ; Does it match
668 jnz .chunk_ready ; If not, this is it
669 add si,4 ; If so, add sector to chunk
670 jmp short .make_chunk
681 ; All loaded up, verify that we got what we needed.
682 ; Note: the checksum field is embedded in the checksum region, so
683 ; by the time we get to the end it should all cancel out.
688 mov edx,-LDLINUX_MAGIC
694 and edx,edx ; Should be zero
695 jz all_read ; We're cool, go for it!
698 ; Uh-oh, something went bad...
700 mov si,checksumerr_msg
705 ; -----------------------------------------------------------------------------
706 ; Subroutines that have to be in the first sector
707 ; -----------------------------------------------------------------------------
711 ; writestr: write a null-terminated string to the console
712 ; This assumes we're on page 0. This is only used for early
713 ; messages, so it should be OK.
719 mov ah,0Eh ; Write to screen as TTY
720 mov bx,0007h ; Attribute
726 ; getlinsecsr: save registers, call getlinsec, restore registers
734 ; Checksum error message
736 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
741 cbios_name db 'CBIOS', 0
742 ebios_name db 'EBIOS', 0
749 cmp word [Debug_Magic],0D00Dh
754 rl_checkpt equ $ ; Must be <= 8000h
756 rl_checkpt_off equ ($-$$)
758 %if rl_checkpt_off > 400h
759 %error "Sector 1 overflow"
763 ; ----------------------------------------------------------------------------
764 ; End of code and data that have to be in the first sector
765 ; ----------------------------------------------------------------------------
769 ; Let the user (and programmer!) know we got this far. This used to be
770 ; in Sector 1, but makes a lot more sense here.
777 ; Insane hack to expand the superblock to dwords
783 mov cx,superinfo_size
787 stosd ; Store expanded word
789 stosd ; Store expanded byte
793 ; Compute some information about this filesystem.
796 ; First, generate the map of regions
801 mov edx,[bsHugeSectors]
803 mov [TotalSectors],edx
805 mov eax,[bxResSectors]
806 mov [FAT],eax ; Beginning of FAT
810 mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
814 mov [RootDirArea],eax ; Beginning of root directory
815 mov [RootDir],eax ; For FAT12/16 == root dir location
817 mov edx,[bxRootDirEnts]
818 add dx,SECTOR_SIZE/32-1
819 shr dx,SECTOR_SHIFT-5
820 mov [RootDirSize],edx
822 mov [DataArea],eax ; Beginning of data area
824 ; Next, generate a cluster size shift count and mask
825 mov eax,[bxSecPerClust]
830 mov [ClustByteShift],cl
839 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
842 mov eax,[TotalSectors]
844 shr eax,cl ; cl == ClustShift
845 mov cl,nextcluster_fat12-(nextcluster+2)
846 cmp eax,4085 ; FAT12 limit
848 mov cl,nextcluster_fat16-(nextcluster+2)
849 cmp eax,65525 ; FAT16 limit
852 ; FAT32, root directory is a cluster chain
855 mov eax,[bootsec+44] ; Root directory cluster
860 mov cl,nextcluster_fat28-(nextcluster+2)
862 mov byte [nextcluster+1],cl
865 ; Common initialization code
867 %include "cpuinit.inc"
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
899 mov si,config_name ; Save configuration file name
913 mov eax,[PrevDir] ; Make the directory with syslinux.cfg ...
914 mov [CurrentDir],eax ; ... the current directory
917 ; Now we have the config file open. Parse the config file and
918 ; run the user interface.
923 ; allocate_file: Allocate a file structure
936 .check: cmp dword [bx], byte 0
938 add bx,open_file_t_size ; ZF = 0
940 ; ZF = 0 if we fell out of the loop
946 ; Search a specific directory for a pre-mangled filename in
947 ; MangledBuf, in the directory starting in sector EAX.
949 ; NOTE: This file considers finding a zero-length file an
950 ; error. This is so we don't have to deal with that special
951 ; case elsewhere in the program (most loops have the test
954 ; Assumes DS == ES == CS.
959 ; EAX = file length (MAY BE ZERO!)
960 ; DL = file attributes
977 ; EAX <- directory sector to scan
979 ; GS:SI now points to this sector
981 mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
984 jz .failure ; Hit directory high water mark
985 test byte [gs:si+11],8 ; Ignore volume labels and
986 ; VFAT long filename entries
1003 jnc .scansector ; CF is set if we're at end
1005 ; If we get here, we failed
1012 xor eax,eax ; ZF <- 1
1015 mov eax,[gs:si+28] ; File size
1016 add eax,SECTOR_SIZE-1
1017 shr eax,SECTOR_SHIFT
1018 mov [bx+4],eax ; Sector count
1021 mov dx,[gs:si+20] ; High cluster word
1023 mov dx,[gs:si+26] ; Low cluster word
1027 mov [bx],edx ; Starting sector
1029 mov eax,[gs:si+28] ; File length again
1030 mov dl,[gs:si+11] ; File attribute
1031 mov si,bx ; File pointer...
1042 ; Deallocates a file structure (pointer in SI)
1048 mov dword [si],0 ; First dword == file_left
1061 ; DX:AX or EAX = file length in bytes
1065 ; Assumes CS == DS == ES, and trashes BX and CX.
1068 mov eax,[CurrentDir]
1069 cmp byte [di],'/' ; Root directory?
1076 push eax ; <A> Current directory sector
1086 pop eax ; <A> Current directory sector
1088 mov [PrevDir],eax ; Remember last directory searched
1091 call mangle_dos_name ; MangledBuf <- component
1094 jz .notfound ; Pathname component missing
1096 cmp byte [di-1],'/' ; Do we expect a directory
1099 ; Otherwise, it should be a file
1101 test dl,18h ; Subdirectory|Volume Label
1102 jnz .badfile ; If not a file, it's a bad thing
1104 ; SI and EAX are already set
1106 shr edx,16 ; Old 16-bit remnant...
1107 and eax,eax ; EAX != 0
1111 ; If we expected a directory, it better be one...
1113 test dl,10h ; Subdirectory
1117 xchg eax,[si+file_sector] ; Get sector number and free file structure
1118 jmp .pathwalk ; Walk the next bit of the path
1122 mov [si],eax ; Free file structure
1131 CurrentDir resd 1 ; Current directory
1132 PrevDir resd 1 ; Last scanned directory
1138 ; kaboom2: once everything is loaded, replace the part of kaboom
1139 ; starting with "kaboom.patch" with this part
1142 mov si,err_bootfailed
1144 cmp byte [kaboom.again+1],18h ; INT 18h version?
1148 int 19h ; And try once more to boot...
1149 .norge: jmp short .norge ; If int 19h returned; this is the end
1153 .noreg: jmp short .noreg ; Nynorsk
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.
1160 ; This verifies that a filename is < FILENAME_MAX characters,
1161 ; doesn't contain whitespace, zero-pads the output buffer,
1162 ; and removes trailing dots and redundant slashes, plus changes
1163 ; backslashes to forward slashes,
1164 ; so "repe cmpsb" can do a compare, and the path-searching routine
1165 ; gets a bit of an easier job.
1172 mov cx,FILENAME_MAX-1
1177 cmp al,' ' ; If control or space, end
1179 cmp al,'\' ; Backslash?
1181 mov al,'/' ; Change to forward slash
1183 cmp al,ah ; Repeated slash?
1190 .mn_skip: loop .mn_loop
1192 cmp bx,di ; At the beginning of the buffer?
1194 cmp byte [es:di-1],'.' ; Terminal dot?
1196 cmp byte [es:di-1],'/' ; Terminal slash?
1198 .mn_kill: dec di ; If so, remove it
1202 inc cx ; At least one null byte
1203 xor ax,ax ; Zero-fill name
1210 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1211 ; filename to the conventional representation. This is needed
1212 ; for the BOOT_IMAGE= parameter for the kernel.
1213 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1214 ; known to be shorter.
1216 ; DS:SI -> input mangled file name
1217 ; ES:DI -> output buffer
1219 ; On return, DI points to the first byte after the output name,
1220 ; which is set to a null byte.
1222 unmangle_name: call strcpy
1223 dec di ; Point to final null byte
1228 ; Mangle a DOS filename component pointed to by DS:SI
1229 ; into [MangledBuf]; ends on encountering any whitespace or slash.
1230 ; Assumes CS == DS == ES.
1237 mov cx,11 ; # of bytes to write
1240 cmp al,' ' ; If control or space, end
1242 cmp al,'/' ; Slash, too
1244 cmp al,'.' ; Period -> space-fill
1251 jmp short .not_lower
1252 .is_period: mov al,' ' ; We need to space-fill
1253 .period_loop: cmp cx,3 ; If <= 3 characters left
1254 jbe .loop ; Just ignore it
1255 stosb ; Otherwise, write a period
1256 loop .period_loop ; Dec CX and (always) jump
1257 .not_uslower: cmp al,ucase_low
1261 mov bx,ucase_tab-ucase_low
1264 loop .loop ; Don't continue if too long
1266 mov al,' ' ; Space-fill name
1267 rep stosb ; Doesn't do anything if CX=0
1276 ; Case tables for extended characters; this is technically code page 865,
1277 ; but code page 437 users will probably not miss not being able to use the
1278 ; cent sign in kernel images too much :-)
1280 ; The table only covers the range 129 to 164; the rest we can deal with.
1286 ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1287 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1288 db 157, 156, 157, 158, 159, 'AIOU', 165
1292 ; getfssec_edx: Get multiple sectors from a file
1294 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1295 ; and will correct the situation if it does, UNLESS *sectors* cross
1299 ; EDX -> Current sector number
1300 ; CX -> Sector count (0FFFFh = until end of file)
1301 ; Must not exceed the ES segment
1302 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1303 ; All arguments are advanced to reflect data read.
1309 xor ebp,ebp ; Fragment sector count
1310 push edx ; Starting sector pointer
1318 add ax,bx ; Now AX = how far into 64K block we are
1319 not ax ; Bytes left in 64K block
1321 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1323 jnb .do_read ; Unless there is at least 1 more sector room...
1324 mov eax,edx ; Current sector
1325 inc edx ; Predict it's the linearly next sector
1328 cmp edx,eax ; Did it match?
1331 pop eax ; Starting sector pointer
1333 lea eax,[eax+ebp-1] ; This is the last sector actually read
1335 add bx,bp ; Adjust buffer pointer
1351 ; getfssec: Get multiple sectors from a file
1353 ; Same as above, except SI is a pointer to a open_file_t
1356 ; DS:SI -> Pointer to open_file_t
1357 ; CX -> Sector count (0FFFFh = until end of file)
1358 ; Must not exceed the ES segment
1359 ; Returns CF=1 on EOF (not necessarily error)
1360 ; All arguments are advanced to reflect data read.
1378 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1379 ; pointed at in the FAT tables. CF=0 on return if end of file.
1382 jmp strict short nextcluster_fat28 ; This gets patched
1392 pushf ; Save the shifted-out LSB (=CF)
1421 ; FAT16 decoding routine.
1428 shr eax,SECTOR_SHIFT-1
1433 movzx edi,word [gs:si+bx]
1440 ; FAT28 ("FAT32") decoding routine.
1447 shr eax,SECTOR_SHIFT-2
1453 mov edi,dword [gs:si+bx]
1454 and edi,0FFFFFFFh ; 28 bits only
1462 ; nextsector: Given a sector in EAX on input, return the next sector
1463 ; of the same filesystem object, which may be the root
1464 ; directory or a cluster chain. Returns EOF.
1484 test edi,[ClustMask]
1487 ; It's not the final sector in a cluster
1492 push gs ; nextcluster trashes gs
1499 ; Now EDI contains the cluster number
1502 jc .exit ; There isn't anything else...
1504 ; New cluster number now in EDI
1506 shl edi,cl ; CF <- 0, unless something is very wrong
1517 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1518 ; and return a pointer in GS:SI, loading it if needed.
1523 add eax,[FAT] ; FAT starting address
1526 ; -----------------------------------------------------------------------------
1528 ; -----------------------------------------------------------------------------
1530 %include "getc.inc" ; getc et al
1531 %include "conio.inc" ; Console I/O
1532 %include "plaincon.inc" ; writechr
1533 %include "writestr.inc" ; String output
1534 %include "configinit.inc" ; Initialize configuration
1535 %include "parseconfig.inc" ; High-level config file handling
1536 %include "parsecmd.inc" ; Low-level config file handling
1537 %include "bcopy32.inc" ; 32-bit bcopy
1538 %include "loadhigh.inc" ; Load a file into high memory
1539 %include "font.inc" ; VGA font stuff
1540 %include "graphics.inc" ; VGA graphics
1541 %include "highmem.inc" ; High memory sizing
1542 %include "strcpy.inc" ; strcpy()
1543 %include "cache.inc" ; Metadata disk cache
1544 %include "adv.inc" ; Auxillary Data Vector
1546 ; -----------------------------------------------------------------------------
1547 ; Begin data section
1548 ; -----------------------------------------------------------------------------
1551 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1553 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1554 db 'a key to continue.', CR, LF, 0
1555 syslinux_cfg1 db '/boot' ; /boot/syslinux/syslinux.cfg
1556 syslinux_cfg2 db '/syslinux' ; /syslinux/syslinux.cfg
1557 syslinux_cfg3 db '/' ; /syslinux.cfg
1558 config_name db 'syslinux.cfg', 0 ; syslinux.cfg
1561 ; Command line options we'd like to take a look at
1563 ; mem= and vga= are handled as normal 32-bit integer values
1564 initrd_cmd db 'initrd='
1565 initrd_cmd_len equ 7
1568 ; Config file keyword table
1570 %include "keywords.inc"
1573 ; Extensions to search for (in *forward* order).
1575 exten_table: db '.cbt' ; COMBOOT (specific)
1576 db '.bss' ; Boot Sector (add superblock)
1577 db '.bs', 0 ; Boot Sector
1578 db '.com' ; COMBOOT (same as DOS)
1581 dd 0, 0 ; Need 8 null bytes here
1584 ; Misc initialized (data) variables
1586 %ifdef debug ; This code for debugging only
1587 debug_magic dw 0D00Dh ; Debug code sentinel
1591 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1592 BufSafeBytes dw trackbufsize ; = how many bytes?
1594 %if ( trackbufsize % SECTOR_SIZE ) != 0
1595 %error trackbufsize must be a multiple of SECTOR_SIZE