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 in high memory 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 3000h
82 cache_seg
equ 2000h ; 64K area for metadata cache
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
115 ; Expanded superblock
117 resq
16 ; The first 16 bytes expanded 8 times
118 FAT resd
1 ; Location of (first) FAT
119 RootDirArea resd
1 ; Location of root directory area
120 RootDir resd
1 ; Location of root directory proper
121 DataArea resd
1 ; Location of data area
122 RootDirSize resd
1 ; Root dir size in sectors
123 TotalSectors resd
1 ; Total number of sectors
124 ClustSize resd
1 ; Bytes/cluster
125 ClustMask resd
1 ; Sectors/cluster - 1
126 CopySuper resb
1 ; Distinguish .bs versus .bss
127 DriveNumber resb
1 ; BIOS drive number
128 ClustShift resb
1 ; Shift count for sectors/cluster
129 ClustByteShift resb
1 ; Shift count for bytes/cluster
131 alignb open_file_t_size
132 Files resb MAX_OPEN
*open_file_t_size
136 ; Some of the things that have to be saved very early are saved
137 ; "close" to the initial stack pointer offset, in order to
138 ; reduce the code size...
140 StackBuf
equ $
-44-32 ; Start the stack here (grow down - 4K)
141 PartInfo
equ StackBuf
; Saved partition table entry
142 FloppyTable
equ PartInfo
+16 ; Floppy info table (must follow PartInfo)
143 OrigFDCTabPtr
equ StackBuf
-8 ; The 2nd high dword on the stack
144 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
147 ; Primary entry point. Tempting as though it may be, we can't put the
148 ; initial "cli" here; the jmp opcode in the first byte is part of the
149 ; "magic number" (using the term very loosely) for the DOS superblock.
152 jmp short start
; 2 bytes
155 ; "Superblock" follows -- it's in the boot sector, so it's already
156 ; loaded and ready for us
158 bsOemName
db 'SYSLINUX' ; The SYS command sets this, so...
160 ; These are the fields we actually care about. We end up expanding them
161 ; all to dword size early in the code, so generate labels for both
162 ; the expanded and unexpanded versions.
165 bx %+ %1 equ SuperInfo
+($
-superblock
)*8+4
170 bx %+ %1 equ SuperInfo
+($
-superblock
)*8
175 bx %+ %1 equ $
; no expansion for dwords
190 superinfo_size
equ ($
-superblock
)-1 ; How much to expand
194 ; This is as far as FAT12/16 and FAT32 are consistent
196 zb
54 ; FAT12/16 need 26 more bytes,
197 ; FAT32 need 54 more bytes
198 superblock_len
equ $
-superblock
200 SecPerClust
equ bxSecPerClust
202 ; Note we don't check the constraints above now; we did that at install
206 cli ; No interrupts yet, please
213 mov sp,StackBuf
; Just below BSS
214 push es ; Save initial ES:DI -> $PnP pointer
218 ; DS:SI may contain a partition table entry. Preserve it for us.
220 mov cx,8 ; Save partition info
224 mov ds,ax ; Now we can initialize DS...
227 ; Now sautee the BIOS floppy info block to that it will support decent-
228 ; size transfers; the floppy block is 11 bytes and is stored in the
229 ; INT 1Eh vector (brilliant waste of resources, eh?)
231 ; Of course, if BIOSes had been properly programmed, we wouldn't have
232 ; had to waste precious space with this code.
235 lfs si,[bx] ; FS:SI -> original fdctab
236 push fs ; Save on stack in case we need to bail
239 ; Save the old fdctab even if hard disk so the stack layout
240 ; is the same. The instructions above do not change the flags
241 mov [DriveNumber
],dl ; Save drive number in DL
242 and dl,dl ; If floppy disk (00-7F), assume no
247 mov cl,6 ; 12 bytes (CX == 0)
248 ; es:di -> FloppyTable already
249 ; This should be safe to do now, interrupts are off...
250 mov [bx],di ; FloppyTable
251 mov [bx+2],ax ; Segment 0
252 fs rep movsw ; Faster to move words
253 mov cl,[bsSecPerTrack
] ; Patch the sector count
256 int 13h ; Some BIOSes need this
258 jmp short not_harddisk
260 ; The drive number and possibly partition information was passed to us
261 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
262 ; trust that rather than what the superblock contains.
264 ; Would it be better to zero out bsHidden if we don't have a partition table?
266 ; Note: di points to beyond the end of PartInfo
269 test byte [di-16],7Fh
; Sanity check: "active flag" should
270 jnz no_partition
; be 00 or 80
271 mov eax,[di-8] ; Partition offset (dword)
275 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
276 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
277 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
278 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
280 ; DL == drive # still
287 inc dx ; Contains # of heads - 1
290 mov [bsSecPerTrack
],cx
294 ; Ready to enable interrupts, captain
299 ; Do we have EBIOS (EDD)?
303 mov ah,41h ; EDD existence query
309 test cl,1 ; Extended disk access functionality set
312 ; We have EDD support...
314 mov byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
318 ; Load the first sector of LDLINUX.SYS; this used to be all proper
319 ; with parsing the superblock and root directory; it doesn't fit
320 ; together with EBIOS support, unfortunately.
322 mov eax,[FirstSector
] ; Sector start
323 mov bx,ldlinux_sys
; Where to load it
326 ; Some modicum of integrity checking
327 cmp dword [ldlinux_magic
+4],LDLINUX_MAGIC^HEXDATE
334 ; getonesec: get one disk sector
337 mov bp,1 ; One sector
341 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
342 ; number in EAX into the buffer at ES:BX. We try to optimize
343 ; by loading up to a whole track at a time, but the user
344 ; is responsible for not crossing a 64K boundary.
345 ; (Yes, BP is weird for a count, but it was available...)
347 ; On return, BX points to the first byte after the transferred
350 ; This routine assumes CS == DS, and trashes most registers.
352 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
353 ; that is dead from that point; this saves space. However, please keep
354 ; the order to dst,src to keep things sane.
357 add eax,[bsHidden
] ; Add partition offset
358 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
360 .
jmp: jmp strict
short getlinsec_cbios
365 ; getlinsec implementation for EBIOS (EDD)
369 push bp ; Sectors left
371 call maxtrans
; Enforce maximum transfer size
372 movzx edi,bp ; Sectors we are about to read
389 mov ah,42h ; Extended Read
393 lea sp,[si+16] ; Remove DAPA
396 add eax,edi ; Advance sector pointer
397 sub bp,di ; Sectors left
398 shl di,SECTOR_SHIFT
; 512-byte sectors
399 add bx,di ; Advance buffer pointer
406 ; Some systems seem to get "stuck" in an error state when
407 ; using EBIOS. Doesn't happen when using CBIOS, which is
408 ; good, since some other systems get timeout failures
409 ; waiting for the floppy disk to spin up.
411 pushad ; Try resetting the device
416 loop .retry
; CX-- and jump if not zero
418 ;shr word [MaxTransfer],1 ; Reduce the transfer size
421 ; Total failure. Try falling back to CBIOS.
422 mov byte [getlinsec.
jmp+1],(getlinsec_cbios
-(getlinsec.
jmp+2))
423 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
426 ; ... fall through ...
431 ; getlinsec implementation for legacy CBIOS
440 movzx esi,word [bsSecPerTrack
]
441 movzx edi,word [bsHeads
]
443 ; Dividing by sectors to get (track,sector): we may have
444 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
448 xchg cx,dx ; CX <- sector index (0-based)
451 div edi ; Convert track to head/cyl
453 ; We should test this, but it doesn't fit...
458 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
459 ; BP = sectors to transfer, SI = bsSecPerTrack,
460 ; ES:BX = data target
463 call maxtrans
; Enforce maximum transfer size
465 ; Must not cross track boundaries, so BP <= SI-CX
472 shl ah,6 ; Because IBM was STOOPID
473 ; and thought 8 bits were enough
474 ; then thought 10 bits were enough...
475 inc cx ; Sector numbers are 1-based, sigh
480 xchg ax,bp ; Sector to transfer count
481 mov ah,02h ; Read sectors
489 movzx ecx,al ; ECX <- sectors transferred
490 shl ax,SECTOR_SHIFT
; Convert sectors in AL to bytes in AX
505 xchg ax,bp ; Sectors transferred <- 0
506 shr word [MaxTransfer
],1
508 ; Fall through to disk_error
511 ; kaboom: write a message and bail out.
517 mov sp,StackBuf
-4 ; Reset stack
518 mov ds,si ; Reset data segment
519 pop dword [fdctab
] ; Restore FDC table
520 .
patch: ; When we have full code, intercept here
523 ; Write error message, this assumes screen page 0
527 mov ah,0Eh
; Write to screen as TTY
528 mov bx,0007h ; Attribute
533 .
again: int 16h ; Wait for keypress
534 ; NB: replaced by int 18h if
535 ; chosen at install time..
536 int 19h ; And try once more to boot...
537 .
norge: jmp short .norge
; If int 19h returned; this is the end
540 ; Truncate BP to MaxTransfer
549 ; Error message on failure
551 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
553 ; This fails if the boot sector overflows
556 FirstSector
dd 0xDEADBEEF ; Location of sector 1
557 MaxTransfer
dw 0x007F ; Max transfer size
559 ; This field will be filled in 0xAA55 by the installer, but we abuse it
560 ; to house a pointer to the INT 16h instruction at
561 ; kaboom.again, which gets patched to INT 18h in RAID mode.
562 bootsignature
dw kaboom.again
-bootsec
565 ; ===========================================================================
567 ; ===========================================================================
568 ; Start of LDLINUX.SYS
569 ; ===========================================================================
573 syslinux_banner
db 0Dh, 0Ah
579 db version_str
, ' ', date
, ' ', 0
580 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
583 ldlinux_magic
dd LDLINUX_MAGIC
584 dd LDLINUX_MAGIC^HEXDATE
587 ; This area is patched by the installer. It is found by looking for
588 ; LDLINUX_MAGIC, plus 8 bytes.
591 LDLDwords
dw 0 ; Total dwords starting at ldlinux_sys
592 LDLSectors
dw 0 ; Number of sectors - (bootsec+this sec)
593 CheckSum
dd 0 ; Checksum starting at ldlinux_sys
594 ; value = LDLINUX_MAGIC - [sum of dwords]
596 ; Space for up to 64 sectors, the theoretical maximum
597 SectorPtrs times
64 dd 0
601 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
602 ; instead of 0000:7C00 and the like. We don't want to add anything
603 ; more to the boot sector, so it is written to not assume a fixed
604 ; value in CS, but we don't want to deal with that anymore from now
611 ; Tell the user we got this far
613 mov si,syslinux_banner
617 ; Tell the user if we're using EBIOS or CBIOS
621 cmp byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
629 %define HAVE_BIOSNAME
1
634 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
635 ; sector again, though.
639 mov bx,7C00h
+2*SECTOR_SIZE
; Where we start loading
645 lodsd ; First sector of this chunk
653 inc edx ; Next linear sector
654 cmp [si],edx ; Does it match
655 jnz .chunk_ready
; If not, this is it
656 add si,4 ; If so, add sector to chunk
657 jmp short .make_chunk
668 ; All loaded up, verify that we got what we needed.
669 ; Note: the checksum field is embedded in the checksum region, so
670 ; by the time we get to the end it should all cancel out.
675 mov edx,-LDLINUX_MAGIC
681 and edx,edx ; Should be zero
682 jz all_read
; We're cool, go for it!
685 ; Uh-oh, something went bad...
687 mov si,checksumerr_msg
692 ; -----------------------------------------------------------------------------
693 ; Subroutines that have to be in the first sector
694 ; -----------------------------------------------------------------------------
698 ; writestr: write a null-terminated string to the console
699 ; This assumes we're on page 0. This is only used for early
700 ; messages, so it should be OK.
706 mov ah,0Eh
; Write to screen as TTY
707 mov bx,0007h ; Attribute
713 ; getlinsecsr: save registers, call getlinsec, restore registers
721 ; Checksum error message
723 checksumerr_msg
db ' Load error - ', 0 ; Boot failed appended
728 cbios_name
db 'CBIOS', 0
729 ebios_name
db 'EBIOS', 0
736 cmp word [Debug_Magic
],0D00Dh
741 rl_checkpt
equ $
; Must be <= 8000h
743 rl_checkpt_off
equ ($
-$$
)
745 %if rl_checkpt_off
> 400h
746 %error
"Sector 1 overflow"
750 ; ----------------------------------------------------------------------------
751 ; End of code and data that have to be in the first sector
752 ; ----------------------------------------------------------------------------
756 ; Let the user (and programmer!) know we got this far. This used to be
757 ; in Sector 1, but makes a lot more sense here.
764 ; Insane hack to expand the superblock to dwords
770 mov cx,superinfo_size
774 stosd ; Store expanded word
776 stosd ; Store expanded byte
780 ; Compute some information about this filesystem.
783 ; First, generate the map of regions
788 mov edx,[bsHugeSectors
]
790 mov [TotalSectors
],edx
792 mov eax,[bxResSectors
]
793 mov [FAT
],eax ; Beginning of FAT
797 mov edx,[bootsec
+36] ; FAT32 BPB_FATsz32
801 mov [RootDirArea
],eax ; Beginning of root directory
802 mov [RootDir
],eax ; For FAT12/16 == root dir location
804 mov edx,[bxRootDirEnts
]
805 add dx,SECTOR_SIZE
/32-1
806 shr dx,SECTOR_SHIFT
-5
807 mov [RootDirSize
],edx
809 mov [DataArea
],eax ; Beginning of data area
811 ; Next, generate a cluster size shift count and mask
812 mov eax,[bxSecPerClust
]
817 mov [ClustByteShift
],cl
826 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
829 mov eax,[TotalSectors
]
831 shr eax,cl ; cl == ClustShift
832 mov cl,nextcluster_fat12
-(nextcluster
+2)
833 cmp eax,4085 ; FAT12 limit
835 mov cl,nextcluster_fat16
-(nextcluster
+2)
836 cmp eax,65525 ; FAT16 limit
839 ; FAT32, root directory is a cluster chain
842 mov eax,[bootsec
+44] ; Root directory cluster
847 mov cl,nextcluster_fat28
-(nextcluster
+2)
849 mov byte [nextcluster
+1],cl
852 ; Common initialization code
854 %include "cpuinit.inc"
858 ; Initialize the metadata cache
863 ; Now, everything is "up and running"... patch kaboom for more
864 ; verbosity and using the full screen system
867 mov dword [kaboom.patch
],0e9h
+((kaboom2
-(kaboom.patch
+3)) << 8)
870 ; Now we're all set to start with our *real* business. First load the
871 ; configuration file (if any) and parse it.
873 ; In previous versions I avoided using 32-bit registers because of a
874 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
875 ; random. I figure, though, that if there are any of those still left
876 ; they probably won't be trying to install Linux on them...
878 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
879 ; to take'm out. In fact, we may want to put them back if we're going
880 ; to boot ELKS at some point.
884 ; Load configuration file
886 mov si,config_name
; Save configuration file name
900 mov eax,[PrevDir
] ; Make the directory with syslinux.cfg ...
901 mov [CurrentDir
],eax ; ... the current directory
904 ; Now we have the config file open. Parse the config file and
905 ; run the user interface.
910 ; allocate_file: Allocate a file structure
923 .
check: cmp dword [bx], byte 0
925 add bx,open_file_t_size
; ZF = 0
927 ; ZF = 0 if we fell out of the loop
933 ; Search a specific directory for a pre-mangled filename in
934 ; MangledBuf, in the directory starting in sector EAX.
936 ; NOTE: This file considers finding a zero-length file an
937 ; error. This is so we don't have to deal with that special
938 ; case elsewhere in the program (most loops have the test
941 ; Assumes DS == ES == CS.
946 ; EAX = file length (MAY BE ZERO!)
947 ; DL = file attributes
964 ; EAX <- directory sector to scan
966 ; GS:SI now points to this sector
968 mov cx,SECTOR_SIZE
/32 ; 32 == directory entry size
971 jz .failure
; Hit directory high water mark
972 test byte [gs:si+11],8 ; Ignore volume labels and
973 ; VFAT long filename entries
990 jnc .scansector
; CF is set if we're at end
992 ; If we get here, we failed
999 xor eax,eax ; ZF <- 1
1002 mov eax,[gs:si+28] ; File size
1003 add eax,SECTOR_SIZE
-1
1004 shr eax,SECTOR_SHIFT
1005 mov [bx+4],eax ; Sector count
1008 mov dx,[gs:si+20] ; High cluster word
1010 mov dx,[gs:si+26] ; Low cluster word
1014 mov [bx],edx ; Starting sector
1016 mov eax,[gs:si+28] ; File length again
1017 mov dl,[gs:si+11] ; File attribute
1018 mov si,bx ; File pointer...
1029 ; Deallocates a file structure (pointer in SI)
1035 mov dword [si],0 ; First dword == file_left
1048 ; DX:AX or EAX = file length in bytes
1052 ; Assumes CS == DS == ES, and trashes BX and CX.
1055 mov eax,[CurrentDir
]
1056 cmp byte [di],'/' ; Root directory?
1063 push eax ; <A> Current directory sector
1073 pop eax ; <A> Current directory sector
1075 mov [PrevDir
],eax ; Remember last directory searched
1078 call mangle_dos_name
; MangledBuf <- component
1081 jz .notfound
; Pathname component missing
1083 cmp byte [di-1],'/' ; Do we expect a directory
1086 ; Otherwise, it should be a file
1088 test dl,18h ; Subdirectory|Volume Label
1089 jnz .badfile
; If not a file, it's a bad thing
1091 ; SI and EAX are already set
1093 shr edx,16 ; Old 16-bit remnant...
1094 and eax,eax ; EAX != 0
1098 ; If we expected a directory, it better be one...
1100 test dl,10h ; Subdirectory
1104 xchg eax,[si+file_sector
] ; Get sector number and free file structure
1105 jmp .pathwalk
; Walk the next bit of the path
1109 mov [si],eax ; Free file structure
1118 CurrentDir resd
1 ; Current directory
1119 PrevDir resd
1 ; Last scanned directory
1125 ; kaboom2: once everything is loaded, replace the part of kaboom
1126 ; starting with "kaboom.patch" with this part
1129 mov si,err_bootfailed
1131 cmp byte [kaboom.again
+1],18h ; INT 18h version?
1135 int 19h ; And try once more to boot...
1136 .
norge: jmp short .norge
; If int 19h returned; this is the end
1140 .
noreg: jmp short .noreg
; Nynorsk
1143 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1144 ; to by ES:DI; ends on encountering any whitespace.
1147 ; This verifies that a filename is < FILENAME_MAX characters,
1148 ; doesn't contain whitespace, zero-pads the output buffer,
1149 ; and removes trailing dots and redundant slashes, plus changes
1150 ; backslashes to forward slashes,
1151 ; so "repe cmpsb" can do a compare, and the path-searching routine
1152 ; gets a bit of an easier job.
1159 mov cx,FILENAME_MAX
-1
1164 cmp al,' ' ; If control or space, end
1166 cmp al,'\' ; Backslash?
1168 mov al,'/' ; Change to forward slash
1170 cmp al,ah ; Repeated slash?
1177 .mn_skip: loop .mn_loop
1179 cmp bx,di ; At the beginning of the buffer?
1181 cmp byte [es:di-1],'.
' ; Terminal dot?
1183 cmp byte [es:di-1],'/' ; Terminal slash?
1185 .mn_kill: dec di ; If so, remove it
1189 inc cx ; At least one null byte
1190 xor ax,ax ; Zero-fill name
1197 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1198 ; filename to the conventional representation. This is needed
1199 ; for the BOOT_IMAGE= parameter for the kernel.
1200 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1201 ; known to be shorter.
1203 ; DS:SI -> input mangled file name
1204 ; ES:DI -> output buffer
1206 ; On return, DI points to the first byte after the output name,
1207 ; which is set to a null byte.
1209 unmangle_name: call strcpy
1210 dec di ; Point to final null byte
1215 ; Mangle a DOS filename component pointed to by DS:SI
1216 ; into [MangledBuf]; ends on encountering any whitespace or slash.
1217 ; Assumes CS == DS == ES.
1224 mov cx,11 ; # of bytes to write
1227 cmp al,' ' ; If control or space, end
1229 cmp al,'/' ; Slash, too
1231 cmp al,'.
' ; Period -> space-fill
1238 jmp short .not_lower
1239 .is_period: mov al,' ' ; We need to space-fill
1240 .period_loop: cmp cx,3 ; If <= 3 characters left
1241 jbe .loop ; Just ignore it
1242 stosb ; Otherwise, write a period
1243 loop .period_loop ; Dec CX and (always) jump
1244 .not_uslower: cmp al,ucase_low
1248 mov bx,ucase_tab-ucase_low
1251 loop .loop ; Don't continue if too long
1253 mov al,' ' ; Space-fill name
1254 rep stosb ; Doesn't do anything if CX=0
1263 ; Case tables for extended characters; this is technically code page 865,
1264 ; but code page 437 users will probably not miss not being able to use the
1265 ; cent sign in kernel images too much :-)
1267 ; The table only covers the range 129 to 164; the rest we can deal with.
1273 ucase_tab
db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1274 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1275 db 157, 156, 157, 158, 159, 'AIOU', 165
1279 ; getfssec_edx: Get multiple sectors from a file
1281 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1282 ; and will correct the situation if it does, UNLESS *sectors* cross
1286 ; EDX -> Current sector number
1287 ; CX -> Sector count (0FFFFh = until end of file)
1288 ; Must not exceed the ES segment
1289 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1290 ; All arguments are advanced to reflect data read.
1296 xor ebp,ebp ; Fragment sector count
1297 push edx ; Starting sector pointer
1305 add ax,bx ; Now AX = how far into 64K block we are
1306 not ax ; Bytes left in 64K block
1308 shr eax,SECTOR_SHIFT
; Sectors left in 64K block
1310 jnb .do_read
; Unless there is at least 1 more sector room...
1311 mov eax,edx ; Current sector
1312 inc edx ; Predict it's the linearly next sector
1315 cmp edx,eax ; Did it match?
1318 pop eax ; Starting sector pointer
1320 lea eax,[eax+ebp-1] ; This is the last sector actually read
1322 add bx,bp ; Adjust buffer pointer
1338 ; getfssec: Get multiple sectors from a file
1340 ; Same as above, except SI is a pointer to a open_file_t
1343 ; DS:SI -> Pointer to open_file_t
1344 ; CX -> Sector count (0FFFFh = until end of file)
1345 ; Must not exceed the ES segment
1346 ; Returns CF=1 on EOF (not necessarily error)
1347 ; All arguments are advanced to reflect data read.
1365 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1366 ; pointed at in the FAT tables. CF=0 on return if end of file.
1369 jmp strict
short nextcluster_fat28
; This gets patched
1379 pushf ; Save the shifted-out LSB (=CF)
1408 ; FAT16 decoding routine.
1415 shr eax,SECTOR_SHIFT
-1
1420 movzx edi,word [gs:si+bx]
1427 ; FAT28 ("FAT32") decoding routine.
1434 shr eax,SECTOR_SHIFT
-2
1440 mov edi,dword [gs:si+bx]
1441 and edi,0FFFFFFFh
; 28 bits only
1449 ; nextsector: Given a sector in EAX on input, return the next sector
1450 ; of the same filesystem object, which may be the root
1451 ; directory or a cluster chain. Returns EOF.
1471 test edi,[ClustMask
]
1474 ; It's not the final sector in a cluster
1479 push gs ; nextcluster trashes gs
1486 ; Now EDI contains the cluster number
1489 jc .exit
; There isn't anything else...
1491 ; New cluster number now in EDI
1493 shl edi,cl ; CF <- 0, unless something is very wrong
1504 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1505 ; and return a pointer in GS:SI, loading it if needed.
1510 add eax,[FAT
] ; FAT starting address
1513 ; -----------------------------------------------------------------------------
1515 ; -----------------------------------------------------------------------------
1517 %include "getc.inc" ; getc et al
1518 %include "conio.inc" ; Console I/O
1519 %include "plaincon.inc" ; writechr
1520 %include "writestr.inc" ; String output
1521 %include "configinit.inc" ; Initialize configuration
1522 %include "parseconfig.inc" ; High-level config file handling
1523 %include "parsecmd.inc" ; Low-level config file handling
1524 %include "bcopy32.inc" ; 32-bit bcopy
1525 %include "loadhigh.inc" ; Load a file into high memory
1526 %include "font.inc" ; VGA font stuff
1527 %include "graphics.inc" ; VGA graphics
1528 %include "highmem.inc" ; High memory sizing
1529 %include "strcpy.inc" ; strcpy()
1530 %include "cache.inc" ; Metadata disk cache
1531 %include "adv.inc" ; Auxillary Data Vector
1532 %include "localboot.inc" ; Disk-based local boot
1534 ; -----------------------------------------------------------------------------
1535 ; Begin data section
1536 ; -----------------------------------------------------------------------------
1539 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
1541 err_bootfailed
db CR
, LF
, 'Boot failed: please change disks and press '
1542 db 'a key to continue.', CR
, LF
, 0
1543 syslinux_cfg1
db '/boot' ; /boot/syslinux/syslinux.cfg
1544 syslinux_cfg2
db '/syslinux' ; /syslinux/syslinux.cfg
1545 syslinux_cfg3
db '/' ; /syslinux.cfg
1546 config_name
db 'syslinux.cfg', 0 ; syslinux.cfg
1549 ; Command line options we'd like to take a look at
1551 ; mem= and vga= are handled as normal 32-bit integer values
1552 initrd_cmd
db 'initrd='
1553 initrd_cmd_len
equ 7
1556 ; Config file keyword table
1558 %include "keywords.inc"
1561 ; Extensions to search for (in *forward* order).
1563 exten_table: db '.cbt' ; COMBOOT (specific)
1564 db '.bss' ; Boot Sector (add superblock)
1565 db '.bs', 0 ; Boot Sector
1566 db '.com' ; COMBOOT (same as DOS)
1569 dd 0, 0 ; Need 8 null bytes here
1572 ; Misc initialized (data) variables
1574 %ifdef debug
; This code for debugging only
1575 debug_magic
dw 0D00Dh
; Debug code sentinel
1579 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1580 BufSafeBytes
dw trackbufsize
; = how many bytes?
1582 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1583 %error trackbufsize must be a multiple of SECTOR_SIZE