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
111 getcbuf resb trackbufsize
117 ; Expanded superblock
119 resq
16 ; The first 16 bytes expanded 8 times
120 FAT resd
1 ; Location of (first) FAT
121 RootDirArea resd
1 ; Location of root directory area
122 RootDir resd
1 ; Location of root directory proper
123 DataArea resd
1 ; Location of data area
124 RootDirSize resd
1 ; Root dir size in sectors
125 TotalSectors resd
1 ; Total number of sectors
126 ClustSize resd
1 ; Bytes/cluster
127 ClustMask resd
1 ; Sectors/cluster - 1
128 CopySuper resb
1 ; Distinguish .bs versus .bss
129 DriveNumber resb
1 ; BIOS drive number
130 ClustShift resb
1 ; Shift count for sectors/cluster
131 ClustByteShift resb
1 ; Shift count for bytes/cluster
133 alignb open_file_t_size
134 Files resb MAX_OPEN
*open_file_t_size
137 ; Constants for the xfer_buf_seg
139 ; The xfer_buf_seg is also used to store message file buffers. We
140 ; need two trackbuffers (text and graphics), plus a work buffer
141 ; for the graphics decompressor.
143 xbs_textbuf
equ 0 ; Also hard-coded, do not change
144 xbs_vgabuf
equ trackbufsize
145 xbs_vgatmpbuf
equ 2*trackbufsize
150 ; Some of the things that have to be saved very early are saved
151 ; "close" to the initial stack pointer offset, in order to
152 ; reduce the code size...
154 StackBuf
equ $
-44-32 ; Start the stack here (grow down - 4K)
155 PartInfo
equ StackBuf
; Saved partition table entry
156 FloppyTable
equ PartInfo
+16 ; Floppy info table (must follow PartInfo)
157 OrigFDCTabPtr
equ StackBuf
-8 ; The 2nd high dword on the stack
158 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
161 ; Primary entry point. Tempting as though it may be, we can't put the
162 ; initial "cli" here; the jmp opcode in the first byte is part of the
163 ; "magic number" (using the term very loosely) for the DOS superblock.
166 jmp short start
; 2 bytes
169 ; "Superblock" follows -- it's in the boot sector, so it's already
170 ; loaded and ready for us
172 bsOemName
db 'SYSLINUX' ; The SYS command sets this, so...
174 ; These are the fields we actually care about. We end up expanding them
175 ; all to dword size early in the code, so generate labels for both
176 ; the expanded and unexpanded versions.
179 bx %+ %1 equ SuperInfo
+($
-superblock
)*8+4
184 bx %+ %1 equ SuperInfo
+($
-superblock
)*8
189 bx %+ %1 equ $
; no expansion for dwords
204 superinfo_size
equ ($
-superblock
)-1 ; How much to expand
208 ; This is as far as FAT12/16 and FAT32 are consistent
210 zb
54 ; FAT12/16 need 26 more bytes,
211 ; FAT32 need 54 more bytes
212 superblock_len
equ $
-superblock
214 SecPerClust
equ bxSecPerClust
216 ; Note we don't check the constraints above now; we did that at install
220 cli ; No interrupts yet, please
227 mov sp,StackBuf
; Just below BSS
228 push es ; Save initial ES:DI -> $PnP pointer
232 ; DS:SI may contain a partition table entry. Preserve it for us.
234 mov cx,8 ; Save partition info
238 mov ds,ax ; Now we can initialize DS...
241 ; Now sautee the BIOS floppy info block to that it will support decent-
242 ; size transfers; the floppy block is 11 bytes and is stored in the
243 ; INT 1Eh vector (brilliant waste of resources, eh?)
245 ; Of course, if BIOSes had been properly programmed, we wouldn't have
246 ; had to waste precious space with this code.
249 lfs si,[bx] ; FS:SI -> original fdctab
250 push fs ; Save on stack in case we need to bail
253 ; Save the old fdctab even if hard disk so the stack layout
254 ; is the same. The instructions above do not change the flags
255 mov [DriveNumber
],dl ; Save drive number in DL
256 and dl,dl ; If floppy disk (00-7F), assume no
261 mov cl,6 ; 12 bytes (CX == 0)
262 ; es:di -> FloppyTable already
263 ; This should be safe to do now, interrupts are off...
264 mov [bx],di ; FloppyTable
265 mov [bx+2],ax ; Segment 0
266 fs rep movsw ; Faster to move words
267 mov cl,[bsSecPerTrack
] ; Patch the sector count
270 int 13h ; Some BIOSes need this
272 jmp short not_harddisk
274 ; The drive number and possibly partition information was passed to us
275 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
276 ; trust that rather than what the superblock contains.
278 ; Would it be better to zero out bsHidden if we don't have a partition table?
280 ; Note: di points to beyond the end of PartInfo
283 test byte [di-16],7Fh
; Sanity check: "active flag" should
284 jnz no_partition
; be 00 or 80
285 mov eax,[di-8] ; Partition offset (dword)
289 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
290 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
291 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
292 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
294 ; DL == drive # still
301 inc dx ; Contains # of heads - 1
304 mov [bsSecPerTrack
],cx
308 ; Ready to enable interrupts, captain
313 ; Do we have EBIOS (EDD)?
317 mov ah,41h ; EDD existence query
323 test cl,1 ; Extended disk access functionality set
326 ; We have EDD support...
328 mov byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
332 ; Load the first sector of LDLINUX.SYS; this used to be all proper
333 ; with parsing the superblock and root directory; it doesn't fit
334 ; together with EBIOS support, unfortunately.
336 mov eax,[FirstSector
] ; Sector start
337 mov bx,ldlinux_sys
; Where to load it
340 ; Some modicum of integrity checking
341 cmp dword [ldlinux_magic
+4],LDLINUX_MAGIC^HEXDATE
348 ; getonesec: get one disk sector
351 mov bp,1 ; One sector
355 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
356 ; number in EAX into the buffer at ES:BX. We try to optimize
357 ; by loading up to a whole track at a time, but the user
358 ; is responsible for not crossing a 64K boundary.
359 ; (Yes, BP is weird for a count, but it was available...)
361 ; On return, BX points to the first byte after the transferred
364 ; This routine assumes CS == DS, and trashes most registers.
366 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
367 ; that is dead from that point; this saves space. However, please keep
368 ; the order to dst,src to keep things sane.
371 add eax,[bsHidden
] ; Add partition offset
372 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
374 .
jmp: jmp strict
short getlinsec_cbios
379 ; getlinsec implementation for EBIOS (EDD)
383 push bp ; Sectors left
385 call maxtrans
; Enforce maximum transfer size
386 movzx edi,bp ; Sectors we are about to read
403 mov ah,42h ; Extended Read
407 lea sp,[si+16] ; Remove DAPA
410 add eax,edi ; Advance sector pointer
411 sub bp,di ; Sectors left
412 shl di,SECTOR_SHIFT
; 512-byte sectors
413 add bx,di ; Advance buffer pointer
420 ; Some systems seem to get "stuck" in an error state when
421 ; using EBIOS. Doesn't happen when using CBIOS, which is
422 ; good, since some other systems get timeout failures
423 ; waiting for the floppy disk to spin up.
425 pushad ; Try resetting the device
430 loop .retry
; CX-- and jump if not zero
432 ;shr word [MaxTransfer],1 ; Reduce the transfer size
435 ; Total failure. Try falling back to CBIOS.
436 mov byte [getlinsec.
jmp+1],(getlinsec_cbios
-(getlinsec.
jmp+2))
437 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
440 ; ... fall through ...
445 ; getlinsec implementation for legacy CBIOS
454 movzx esi,word [bsSecPerTrack
]
455 movzx edi,word [bsHeads
]
457 ; Dividing by sectors to get (track,sector): we may have
458 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
462 xchg cx,dx ; CX <- sector index (0-based)
465 div edi ; Convert track to head/cyl
467 ; We should test this, but it doesn't fit...
472 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
473 ; BP = sectors to transfer, SI = bsSecPerTrack,
474 ; ES:BX = data target
477 call maxtrans
; Enforce maximum transfer size
479 ; Must not cross track boundaries, so BP <= SI-CX
486 shl ah,6 ; Because IBM was STOOPID
487 ; and thought 8 bits were enough
488 ; then thought 10 bits were enough...
489 inc cx ; Sector numbers are 1-based, sigh
494 xchg ax,bp ; Sector to transfer count
495 mov ah,02h ; Read sectors
503 movzx ecx,al ; ECX <- sectors transferred
504 shl ax,SECTOR_SHIFT
; Convert sectors in AL to bytes in AX
519 xchg ax,bp ; Sectors transferred <- 0
520 shr word [MaxTransfer
],1
522 ; Fall through to disk_error
525 ; kaboom: write a message and bail out.
531 mov sp,StackBuf
-4 ; Reset stack
532 mov ds,si ; Reset data segment
533 pop dword [fdctab
] ; Restore FDC table
534 .
patch: ; When we have full code, intercept here
537 ; Write error message, this assumes screen page 0
541 mov ah,0Eh
; Write to screen as TTY
542 mov bx,0007h ; Attribute
547 .
again: int 16h ; Wait for keypress
548 ; NB: replaced by int 18h if
549 ; chosen at install time..
550 int 19h ; And try once more to boot...
551 .
norge: jmp short .norge
; If int 19h returned; this is the end
554 ; Truncate BP to MaxTransfer
563 ; Error message on failure
565 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
567 ; This fails if the boot sector overflows
570 FirstSector
dd 0xDEADBEEF ; Location of sector 1
571 MaxTransfer
dw 0x007F ; Max transfer size
573 ; This field will be filled in 0xAA55 by the installer, but we abuse it
574 ; to house a pointer to the INT 16h instruction at
575 ; kaboom.again, which gets patched to INT 18h in RAID mode.
576 bootsignature
dw kaboom.again
-bootsec
579 ; ===========================================================================
581 ; ===========================================================================
582 ; Start of LDLINUX.SYS
583 ; ===========================================================================
587 syslinux_banner
db 0Dh, 0Ah
593 db version_str
, ' ', date
, ' ', 0
594 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
597 ldlinux_magic
dd LDLINUX_MAGIC
598 dd LDLINUX_MAGIC^HEXDATE
601 ; This area is patched by the installer. It is found by looking for
602 ; LDLINUX_MAGIC, plus 8 bytes.
605 LDLDwords
dw 0 ; Total dwords starting at ldlinux_sys
606 LDLSectors
dw 0 ; Number of sectors - (bootsec+this sec)
607 CheckSum
dd 0 ; Checksum starting at ldlinux_sys
608 ; value = LDLINUX_MAGIC - [sum of dwords]
610 ; Space for up to 64 sectors, the theoretical maximum
611 SectorPtrs times
64 dd 0
615 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
616 ; instead of 0000:7C00 and the like. We don't want to add anything
617 ; more to the boot sector, so it is written to not assume a fixed
618 ; value in CS, but we don't want to deal with that anymore from now
625 ; Tell the user we got this far
627 mov si,syslinux_banner
631 ; Tell the user if we're using EBIOS or CBIOS
635 cmp byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
643 %define HAVE_BIOSNAME
1
648 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
649 ; sector again, though.
653 mov bx,7C00h
+2*SECTOR_SIZE
; Where we start loading
659 lodsd ; First sector of this chunk
667 inc edx ; Next linear sector
668 cmp [si],edx ; Does it match
669 jnz .chunk_ready
; If not, this is it
670 add si,4 ; If so, add sector to chunk
671 jmp short .make_chunk
682 ; All loaded up, verify that we got what we needed.
683 ; Note: the checksum field is embedded in the checksum region, so
684 ; by the time we get to the end it should all cancel out.
689 mov edx,-LDLINUX_MAGIC
695 and edx,edx ; Should be zero
696 jz all_read
; We're cool, go for it!
699 ; Uh-oh, something went bad...
701 mov si,checksumerr_msg
706 ; -----------------------------------------------------------------------------
707 ; Subroutines that have to be in the first sector
708 ; -----------------------------------------------------------------------------
712 ; writestr: write a null-terminated string to the console
713 ; This assumes we're on page 0. This is only used for early
714 ; messages, so it should be OK.
720 mov ah,0Eh
; Write to screen as TTY
721 mov bx,0007h ; Attribute
727 ; getlinsecsr: save registers, call getlinsec, restore registers
735 ; Checksum error message
737 checksumerr_msg
db ' Load error - ', 0 ; Boot failed appended
742 cbios_name
db 'CBIOS', 0
743 ebios_name
db 'EBIOS', 0
750 cmp word [Debug_Magic
],0D00Dh
755 rl_checkpt
equ $
; Must be <= 8000h
757 rl_checkpt_off
equ ($
-$$
)
759 %if rl_checkpt_off
> 400h
760 %error
"Sector 1 overflow"
764 ; ----------------------------------------------------------------------------
765 ; End of code and data that have to be in the first sector
766 ; ----------------------------------------------------------------------------
770 ; Let the user (and programmer!) know we got this far. This used to be
771 ; in Sector 1, but makes a lot more sense here.
778 ; Insane hack to expand the superblock to dwords
784 mov cx,superinfo_size
788 stosd ; Store expanded word
790 stosd ; Store expanded byte
794 ; Compute some information about this filesystem.
797 ; First, generate the map of regions
802 mov edx,[bsHugeSectors
]
804 mov [TotalSectors
],edx
806 mov eax,[bxResSectors
]
807 mov [FAT
],eax ; Beginning of FAT
811 mov edx,[bootsec
+36] ; FAT32 BPB_FATsz32
815 mov [RootDirArea
],eax ; Beginning of root directory
816 mov [RootDir
],eax ; For FAT12/16 == root dir location
818 mov edx,[bxRootDirEnts
]
819 add dx,SECTOR_SIZE
/32-1
820 shr dx,SECTOR_SHIFT
-5
821 mov [RootDirSize
],edx
823 mov [DataArea
],eax ; Beginning of data area
825 ; Next, generate a cluster size shift count and mask
826 mov eax,[bxSecPerClust
]
831 mov [ClustByteShift
],cl
840 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
843 mov eax,[TotalSectors
]
845 shr eax,cl ; cl == ClustShift
846 mov cl,nextcluster_fat12
-(nextcluster
+2)
847 cmp eax,4085 ; FAT12 limit
849 mov cl,nextcluster_fat16
-(nextcluster
+2)
850 cmp eax,65525 ; FAT16 limit
853 ; FAT32, root directory is a cluster chain
856 mov eax,[bootsec
+44] ; Root directory cluster
861 mov cl,nextcluster_fat28
-(nextcluster
+2)
863 mov byte [nextcluster
+1],cl
866 ; Common initialization code
868 %include "cpuinit.inc"
872 ; Initialize the metadata cache
877 ; Now, everything is "up and running"... patch kaboom for more
878 ; verbosity and using the full screen system
881 mov dword [kaboom.patch
],0e9h
+((kaboom2
-(kaboom.patch
+3)) << 8)
884 ; Now we're all set to start with our *real* business. First load the
885 ; configuration file (if any) and parse it.
887 ; In previous versions I avoided using 32-bit registers because of a
888 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
889 ; random. I figure, though, that if there are any of those still left
890 ; they probably won't be trying to install Linux on them...
892 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
893 ; to take'm out. In fact, we may want to put them back if we're going
894 ; to boot ELKS at some point.
898 ; Load configuration file
900 mov si,config_name
; Save configuration file name
914 mov eax,[PrevDir
] ; Make the directory with syslinux.cfg ...
915 mov [CurrentDir
],eax ; ... the current directory
918 ; Now we have the config file open. Parse the config file and
919 ; run the user interface.
924 ; allocate_file: Allocate a file structure
937 .
check: cmp dword [bx], byte 0
939 add bx,open_file_t_size
; ZF = 0
941 ; ZF = 0 if we fell out of the loop
947 ; Search a specific directory for a pre-mangled filename in
948 ; MangledBuf, in the directory starting in sector EAX.
950 ; NOTE: This file considers finding a zero-length file an
951 ; error. This is so we don't have to deal with that special
952 ; case elsewhere in the program (most loops have the test
955 ; Assumes DS == ES == CS.
960 ; EAX = file length (MAY BE ZERO!)
961 ; DL = file attributes
978 ; EAX <- directory sector to scan
980 ; GS:SI now points to this sector
982 mov cx,SECTOR_SIZE
/32 ; 32 == directory entry size
985 jz .failure
; Hit directory high water mark
986 test byte [gs:si+11],8 ; Ignore volume labels and
987 ; VFAT long filename entries
1004 jnc .scansector
; CF is set if we're at end
1006 ; If we get here, we failed
1013 xor eax,eax ; ZF <- 1
1016 mov eax,[gs:si+28] ; File size
1017 add eax,SECTOR_SIZE
-1
1018 shr eax,SECTOR_SHIFT
1019 mov [bx+4],eax ; Sector count
1022 mov dx,[gs:si+20] ; High cluster word
1024 mov dx,[gs:si+26] ; Low cluster word
1028 mov [bx],edx ; Starting sector
1030 mov eax,[gs:si+28] ; File length again
1031 mov dl,[gs:si+11] ; File attribute
1032 mov si,bx ; File pointer...
1043 ; Deallocates a file structure (pointer in SI)
1049 mov dword [si],0 ; First dword == file_left
1062 ; DX:AX or EAX = file length in bytes
1066 ; Assumes CS == DS == ES, and trashes BX and CX.
1069 mov eax,[CurrentDir
]
1070 cmp byte [di],'/' ; Root directory?
1077 push eax ; <A> Current directory sector
1087 pop eax ; <A> Current directory sector
1089 mov [PrevDir
],eax ; Remember last directory searched
1092 call mangle_dos_name
; MangledBuf <- component
1095 jz .notfound
; Pathname component missing
1097 cmp byte [di-1],'/' ; Do we expect a directory
1100 ; Otherwise, it should be a file
1102 test dl,18h ; Subdirectory|Volume Label
1103 jnz .badfile
; If not a file, it's a bad thing
1105 ; SI and EAX are already set
1107 shr edx,16 ; Old 16-bit remnant...
1108 and eax,eax ; EAX != 0
1112 ; If we expected a directory, it better be one...
1114 test dl,10h ; Subdirectory
1118 xchg eax,[si+file_sector
] ; Get sector number and free file structure
1119 jmp .pathwalk
; Walk the next bit of the path
1123 mov [si],eax ; Free file structure
1132 CurrentDir resd
1 ; Current directory
1133 PrevDir resd
1 ; Last scanned directory
1139 ; kaboom2: once everything is loaded, replace the part of kaboom
1140 ; starting with "kaboom.patch" with this part
1143 mov si,err_bootfailed
1145 cmp byte [kaboom.again
+1],18h ; INT 18h version?
1149 int 19h ; And try once more to boot...
1150 .
norge: jmp short .norge
; If int 19h returned; this is the end
1154 .
noreg: jmp short .noreg
; Nynorsk
1157 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1158 ; to by ES:DI; ends on encountering any whitespace.
1161 ; This verifies that a filename is < FILENAME_MAX characters,
1162 ; doesn't contain whitespace, zero-pads the output buffer,
1163 ; and removes trailing dots and redundant slashes, plus changes
1164 ; backslashes to forward slashes,
1165 ; so "repe cmpsb" can do a compare, and the path-searching routine
1166 ; gets a bit of an easier job.
1173 mov cx,FILENAME_MAX
-1
1178 cmp al,' ' ; If control or space, end
1180 cmp al,'\' ; Backslash?
1182 mov al,'/' ; Change to forward slash
1184 cmp al,ah ; Repeated slash?
1191 .mn_skip: loop .mn_loop
1193 cmp bx,di ; At the beginning of the buffer?
1195 cmp byte [es:di-1],'.
' ; Terminal dot?
1197 cmp byte [es:di-1],'/' ; Terminal slash?
1199 .mn_kill: dec di ; If so, remove it
1203 inc cx ; At least one null byte
1204 xor ax,ax ; Zero-fill name
1211 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1212 ; filename to the conventional representation. This is needed
1213 ; for the BOOT_IMAGE= parameter for the kernel.
1214 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1215 ; known to be shorter.
1217 ; DS:SI -> input mangled file name
1218 ; ES:DI -> output buffer
1220 ; On return, DI points to the first byte after the output name,
1221 ; which is set to a null byte.
1223 unmangle_name: call strcpy
1224 dec di ; Point to final null byte
1229 ; Mangle a DOS filename component pointed to by DS:SI
1230 ; into [MangledBuf]; ends on encountering any whitespace or slash.
1231 ; Assumes CS == DS == ES.
1238 mov cx,11 ; # of bytes to write
1241 cmp al,' ' ; If control or space, end
1243 cmp al,'/' ; Slash, too
1245 cmp al,'.
' ; Period -> space-fill
1252 jmp short .not_lower
1253 .is_period: mov al,' ' ; We need to space-fill
1254 .period_loop: cmp cx,3 ; If <= 3 characters left
1255 jbe .loop ; Just ignore it
1256 stosb ; Otherwise, write a period
1257 loop .period_loop ; Dec CX and (always) jump
1258 .not_uslower: cmp al,ucase_low
1262 mov bx,ucase_tab-ucase_low
1265 loop .loop ; Don't continue if too long
1267 mov al,' ' ; Space-fill name
1268 rep stosb ; Doesn't do anything if CX=0
1277 ; Case tables for extended characters; this is technically code page 865,
1278 ; but code page 437 users will probably not miss not being able to use the
1279 ; cent sign in kernel images too much :-)
1281 ; The table only covers the range 129 to 164; the rest we can deal with.
1287 ucase_tab
db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1288 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1289 db 157, 156, 157, 158, 159, 'AIOU', 165
1293 ; getfssec_edx: Get multiple sectors from a file
1295 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1296 ; and will correct the situation if it does, UNLESS *sectors* cross
1300 ; EDX -> Current sector number
1301 ; CX -> Sector count (0FFFFh = until end of file)
1302 ; Must not exceed the ES segment
1303 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1304 ; All arguments are advanced to reflect data read.
1310 xor ebp,ebp ; Fragment sector count
1311 push edx ; Starting sector pointer
1319 add ax,bx ; Now AX = how far into 64K block we are
1320 not ax ; Bytes left in 64K block
1322 shr eax,SECTOR_SHIFT
; Sectors left in 64K block
1324 jnb .do_read
; Unless there is at least 1 more sector room...
1325 mov eax,edx ; Current sector
1326 inc edx ; Predict it's the linearly next sector
1329 cmp edx,eax ; Did it match?
1332 pop eax ; Starting sector pointer
1334 lea eax,[eax+ebp-1] ; This is the last sector actually read
1336 add bx,bp ; Adjust buffer pointer
1352 ; getfssec: Get multiple sectors from a file
1354 ; Same as above, except SI is a pointer to a open_file_t
1357 ; DS:SI -> Pointer to open_file_t
1358 ; CX -> Sector count (0FFFFh = until end of file)
1359 ; Must not exceed the ES segment
1360 ; Returns CF=1 on EOF (not necessarily error)
1361 ; All arguments are advanced to reflect data read.
1379 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1380 ; pointed at in the FAT tables. CF=0 on return if end of file.
1383 jmp strict
short nextcluster_fat28
; This gets patched
1393 pushf ; Save the shifted-out LSB (=CF)
1422 ; FAT16 decoding routine.
1429 shr eax,SECTOR_SHIFT
-1
1434 movzx edi,word [gs:si+bx]
1441 ; FAT28 ("FAT32") decoding routine.
1448 shr eax,SECTOR_SHIFT
-2
1454 mov edi,dword [gs:si+bx]
1455 and edi,0FFFFFFFh
; 28 bits only
1463 ; nextsector: Given a sector in EAX on input, return the next sector
1464 ; of the same filesystem object, which may be the root
1465 ; directory or a cluster chain. Returns EOF.
1485 test edi,[ClustMask
]
1488 ; It's not the final sector in a cluster
1493 push gs ; nextcluster trashes gs
1500 ; Now EDI contains the cluster number
1503 jc .exit
; There isn't anything else...
1505 ; New cluster number now in EDI
1507 shl edi,cl ; CF <- 0, unless something is very wrong
1518 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1519 ; and return a pointer in GS:SI, loading it if needed.
1524 add eax,[FAT
] ; FAT starting address
1527 ; -----------------------------------------------------------------------------
1529 ; -----------------------------------------------------------------------------
1531 %include "getc.inc" ; getc et al
1532 %include "conio.inc" ; Console I/O
1533 %include "plaincon.inc" ; writechr
1534 %include "writestr.inc" ; String output
1535 %include "configinit.inc" ; Initialize configuration
1536 %include "parseconfig.inc" ; High-level config file handling
1537 %include "parsecmd.inc" ; Low-level config file handling
1538 %include "bcopy32.inc" ; 32-bit bcopy
1539 %include "loadhigh.inc" ; Load a file into high memory
1540 %include "font.inc" ; VGA font stuff
1541 %include "graphics.inc" ; VGA graphics
1542 %include "highmem.inc" ; High memory sizing
1543 %include "strcpy.inc" ; strcpy()
1544 %include "cache.inc" ; Metadata disk cache
1545 %include "adv.inc" ; Auxillary Data Vector
1547 ; -----------------------------------------------------------------------------
1548 ; Begin data section
1549 ; -----------------------------------------------------------------------------
1552 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
1554 err_bootfailed
db CR
, LF
, 'Boot failed: please change disks and press '
1555 db 'a key to continue.', CR
, LF
, 0
1556 syslinux_cfg1
db '/boot' ; /boot/syslinux/syslinux.cfg
1557 syslinux_cfg2
db '/syslinux' ; /syslinux/syslinux.cfg
1558 syslinux_cfg3
db '/' ; /syslinux.cfg
1559 config_name
db 'syslinux.cfg', 0 ; syslinux.cfg
1562 ; Command line options we'd like to take a look at
1564 ; mem= and vga= are handled as normal 32-bit integer values
1565 initrd_cmd
db 'initrd='
1566 initrd_cmd_len
equ 7
1569 ; Config file keyword table
1571 %include "keywords.inc"
1574 ; Extensions to search for (in *forward* order).
1576 exten_table: db '.cbt' ; COMBOOT (specific)
1577 db '.bss' ; Boot Sector (add superblock)
1578 db '.bs', 0 ; Boot Sector
1579 db '.com' ; COMBOOT (same as DOS)
1582 dd 0, 0 ; Need 8 null bytes here
1585 ; Misc initialized (data) variables
1587 %ifdef debug
; This code for debugging only
1588 debug_magic
dw 0D00Dh
; Debug code sentinel
1592 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1593 BufSafeBytes
dw trackbufsize
; = how many bytes?
1595 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1596 %error trackbufsize must be a multiple of SECTOR_SIZE