1 ; -*- fundamental -*- (asm-mode sucks)
3 ; ****************************************************************************
7 ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
8 ; functionality is good to have for installation floppies, where it may
9 ; be hard to find a functional Linux system to run LILO off.
11 ; This program allows manipulation of the disk to take place entirely
12 ; from MS-LOSS, and can be especially useful in conjunction with the
15 ; This file is loaded in stages; first the boot sector at offset 7C00h,
16 ; then the first sector (cluster, really, but we can only assume 1 sector)
17 ; of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h.
19 ; Copyright (C) 1994-2004 H. Peter Anvin
21 ; This program is free software; you can redistribute it and/or modify
22 ; it under the terms of the GNU General Public License as published by
23 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
24 ; Boston MA 02111-1307, USA; either version 2 of the License, or
25 ; (at your option) any later version; incorporated herein by reference.
27 ; ****************************************************************************
36 %include "tracers.inc"
39 ; Some semi-configurable constants... change on your own risk.
42 FILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null)
43 FILENAME_MAX equ 11 ; Max mangled filename size
44 NULLFILE equ ' ' ; First char space == null filename
45 retry_count equ 6 ; How patient are we with the disk?
46 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
47 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
50 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
53 ; This is what we need to do when idle
63 ; The following structure is used for "virtual kernels"; i.e. LILO-style
64 ; option labels. The options we permit here are `kernel' and `append
65 ; Since there is no room in the bottom 64K for all of these, we
66 ; stick them at vk_seg:0000 and copy them down before we need them.
68 ; Note: this structure can be added to, but it must
70 %define vk_power 7 ; log2(max number of vkernels)
71 %define max_vk (1 << vk_power) ; Maximum number of vkernels
72 %define vk_shift (16-vk_power) ; Number of bits to shift
73 %define vk_size (1 << vk_shift) ; Size of a vkernel buffer
76 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
77 vk_rname: resb FILENAME_MAX ; Real name
80 vk_append: resb max_cmd_len+1 ; Command line
82 vk_end: equ $ ; Should be <= vk_size
86 %if (vk_end > vk_size) || (vk_size*max_vk > 65536)
87 %error "Too many vkernels defined, reduce vk_power"
92 ; Segment assignments in the bottom 640K
93 ; Stick to the low 512K in case we're using something like M-systems flash
94 ; which load a driver into low RAM (evil!!)
96 ; 0000h - main code/data segment (and BIOS segment)
98 real_mode_seg equ 4000h
99 cache_seg equ 3000h ; 64K area for metadata cache
100 vk_seg equ 2000h ; Virtual kernels
101 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
102 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
104 ; ---------------------------------------------------------------------------
106 ; ---------------------------------------------------------------------------
109 ; Memory below this point is reserved for the BIOS and the MBR
112 trackbufsize equ 8192
113 trackbuf resb trackbufsize ; Track buffer goes here
114 getcbuf resb trackbufsize
119 ; Constants for the xfer_buf_seg
121 ; The xfer_buf_seg is also used to store message file buffers. We
122 ; need two trackbuffers (text and graphics), plus a work buffer
123 ; for the graphics decompressor.
125 xbs_textbuf equ 0 ; Also hard-coded, do not change
126 xbs_vgabuf equ trackbufsize
127 xbs_vgatmpbuf equ 2*trackbufsize
130 absolute 5000h ; Here we keep our BSS stuff
131 VKernelBuf: resb vk_size ; "Current" vkernel
133 AppendBuf resb max_cmd_len+1 ; append=
134 Ontimeout resb max_cmd_len+1 ; ontimeout
135 Onerror resb max_cmd_len+1 ; onerror
136 KbdMap resb 256 ; Keyboard map
137 FKeyName resb 10*16 ; File names for F-key help
138 NumBuf resb 15 ; Buffer to load number
139 NumBufEnd resb 1 ; Last byte in NumBuf
142 ; Expanded superblock
144 resq 16 ; The first 16 bytes expanded 8 times
146 FAT resd 1 ; Location of (first) FAT
147 RootDirArea resd 1 ; Location of root directory area
148 RootDir resd 1 ; Location of root directory proper
149 DataArea resd 1 ; Location of data area
150 RootDirSize resd 1 ; Root dir size in sectors
151 TotalSectors resd 1 ; Total number of sectors
152 EndSector resd 1 ; Location of filesystem end
155 E820Buf resd 5 ; INT 15:E820 data buffer
156 E820Mem resd 1 ; Memory detected by E820
157 E820Max resd 1 ; Is E820 memory capped?
158 HiLoadAddr resd 1 ; Address pointer for high load loop
159 HighMemSize resd 1 ; End of memory pointer (bytes)
160 RamdiskMax resd 1 ; Highest address for a ramdisk
161 KernelSize resd 1 ; Size of kernel (bytes)
162 SavedSSSP resd 1 ; Our SS:SP while running a COMBOOT image
163 PMESP resd 1 ; Protected-mode ESP
164 FSectors resd 1 ; Number of sectors in getc file
165 ClustPerMoby resd 1 ; Clusters per 64K
166 ClustSize resd 1 ; Bytes/cluster
167 ClustMask resd 1 ; Sectors/cluster - 1
168 KernelName resb 12 ; Mangled name for kernel
169 ; (note the spare byte after!)
170 OrigKernelExt resd 1 ; Original kernel extension
171 FBytes equ $ ; Used by open/getc
174 DirBlocksLeft resw 1 ; Ditto
175 RunLinClust resw 1 ; Cluster # for LDLINUX.SYS
176 KernelSects resw 1 ; Kernel size in clusters
177 FNextClust resw 1 ; Pointer to next cluster in d:o
178 FPtr resw 1 ; Pointer to next char in buffer
179 CmdOptPtr resw 1 ; Pointer to first option on cmd line
180 KernelCNameLen resw 1 ; Length of unmangled kernel name
181 InitRDCNameLen resw 1 ; Length of unmangled initrd name
182 NextCharJump resw 1 ; Routine to interpret next print char
183 SetupSecs resw 1 ; Number of setup sectors
184 A20Test resw 1 ; Counter for testing status of A20
185 A20Type resw 1 ; A20 type
186 CmdLineLen resw 1 ; Length of command line including null
187 GraphXSize resw 1 ; Width of splash screen file
188 VGAPos resw 1 ; Pointer into VGA memory
189 VGACluster resw 1 ; Cluster pointer for VGA image file
190 VGAFilePtr resw 1 ; Pointer into VGAFileBuf
191 Com32SysSP resw 1 ; SP saved during COM32 syscall
192 DirScanCtr resw 1 ; OBSOLETE FIX THIS
193 EndofDirSec resw 1 ; OBSOLETE FIX THIS
194 CachePtrs times (65536/SECTOR_SIZE) resw 1
197 CursorCol resb 1 ; Cursor column for message file
198 CursorRow resb 1 ; Cursor row for message file
200 VidCols resb 1 ; Columns on screen-1
201 VidRows resb 1 ; Rows on screen-1
202 BaudDivisor resw 1 ; Baud rate divisor
204 FlowOutput resb 1 ; Outputs to assert for serial flow
205 FlowInput resb 1 ; Input bits for serial flow
206 FlowIgnore resb 1 ; Ignore input unless these bits set
207 TextAttribute resb 1 ; Text attribute for message file
208 RetryCount resb 1 ; Used for disk access retries
209 KbdFlags resb 1 ; Check for keyboard escapes
210 LoadFlags resb 1 ; Loadflags from kernel
211 A20Tries resb 1 ; Times until giving up on A20
212 FuncFlag resb 1 ; Escape sequences received from keyboard
213 DisplayMask resb 1 ; Display modes mask
214 CopySuper resb 1 ; Distinguish .bs versus .bss
215 DriveNumber resb 1 ; BIOS drive number
216 ClustShift resb 1 ; Shift count for sectors/cluster
217 ClustByteShift resb 1 ; Shift count for bytes/cluster
218 MNameBuf resb 11 ; Generic mangled file name buffer
219 InitRD resb 11 ; initrd= mangled name
220 KernelCName resb 13 ; Unmangled kernel name
221 InitRDCName resb 13 ; Unmangled initrd name
222 TextColorReg resb 17 ; VGA color registers for text mode
223 VGAFileBuf resb 13 ; Unmangled VGA image name
225 VGAFileMBuf resb 11 ; Mangled VGA image name
226 alignb 4 ; For the good of REP MOVSD
227 command_line resb max_cmd_len+2 ; Command line buffer
229 default_cmd resb max_cmd_len+1 ; "default" command line
234 ; Some of the things that have to be saved very early are saved
235 ; "close" to the initial stack pointer offset, in order to
236 ; reduce the code size...
238 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
239 PartInfo equ StackBuf ; Saved partition table entry
240 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
241 OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
244 ; Primary entry point. Tempting as though it may be, we can't put the
245 ; initial "cli" here; the jmp opcode in the first byte is part of the
246 ; "magic number" (using the term very loosely) for the DOS superblock.
249 jmp short start ; 2 bytes
252 ; "Superblock" follows -- it's in the boot sector, so it's already
253 ; loaded and ready for us
255 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
257 ; These are the fields we actually care about. We end up expanding them
258 ; all to dword size early in the code, so generate labels for both
259 ; the expanded and unexpanded versions.
262 bx %+ %1 equ SuperInfo+($-superblock)*8+4
267 bx %+ %1 equ SuperInfo+($-superblock)*8
272 bx %+ %1 equ $ ; no expansion for dwords
287 superinfo_size equ ($-superblock)-1 ; How much to expand
291 ; This is as far as FAT12/16 and FAT32 are consistent
293 zb 54 ; FAT12/16 need 26 more bytes,
294 ; FAT32 need 54 more bytes
295 superblock_len equ $-superblock
297 SecPerClust equ bxSecPerClust
299 ; Note we don't check the constraints above now; we did that at install
303 ;floppy_table equ $ ; No sense in wasting memory, overwrite start
306 cli ; No interrupts yet, please
313 mov sp,StackBuf ; Just below BSS
316 ; DS:SI may contain a partition table entry. Preserve it for us.
318 mov cx,8 ; Save partition info
322 mov ds,ax ; Now we can initialize DS...
325 ; Now sautee the BIOS floppy info block to that it will support decent-
326 ; size transfers; the floppy block is 11 bytes and is stored in the
327 ; INT 1Eh vector (brilliant waste of resources, eh?)
329 ; Of course, if BIOSes had been properly programmed, we wouldn't have
330 ; had to waste precious space with this code.
333 lfs si,[bx] ; FS:SI -> original fdctab
334 push fs ; Save on stack in case we need to bail
337 ; Save the old fdctab even if hard disk so the stack layout
338 ; is the same. The instructions above do not change the flags
339 mov [DriveNumber],dl ; Save drive number in DL
340 and dl,dl ; If floppy disk (00-7F), assume no
345 mov cl,6 ; 12 bytes (CX == 0)
346 ; es:di -> FloppyTable already
347 ; This should be safe to do now, interrupts are off...
348 mov [bx],di ; FloppyTable
349 mov [bx+2],ax ; Segment 0
350 fs rep movsw ; Faster to move words
351 mov cl,[bsSecPerTrack] ; Patch the sector count
354 int 13h ; Some BIOSes need this
356 jmp short not_harddisk
358 ; The drive number and possibly partition information was passed to us
359 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
360 ; trust that rather than what the superblock contains.
362 ; Would it be better to zero out bsHidden if we don't have a partition table?
364 ; Note: di points to beyond the end of PartInfo
367 test byte [di-16],7Fh ; Sanity check: "active flag" should
368 jnz no_partition ; be 00 or 80
369 mov eax,[di-8] ; Partition offset (dword)
373 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
374 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
375 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
376 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
378 ; DL == drive # still
385 inc dx ; Contains # of heads - 1
388 mov [bsSecPerTrack],cx
392 ; Ready to enable interrupts, captain
398 ; Do we have EBIOS (EDD)?
402 mov ah,41h ; EDD existence query
408 test cl,1 ; Extended disk access functionality set
411 ; We have EDD support...
413 mov byte [getlinsec+1],getlinsec_ebios-(getlinsec+2)
417 ; Load the first sector of LDLINUX.SYS; this used to be all proper
418 ; with parsing the superblock and root directory; it doesn't fit
419 ; together with EBIOS support, unfortunately.
421 mov eax,[FirstSector] ; Sector start
422 mov bx,ldlinux_sys ; Where to load it
425 ; Some modicum of integrity checking
426 cmp dword [ldlinux_magic],LDLINUX_MAGIC
428 cmp dword [ldlinux_magic+4],HEXDATE
435 ; kaboom: write a message and bail out.
440 mov sp,StackBuf-4 ; Reset stack
441 mov ds,si ; Reset data segment
442 pop dword [fdctab] ; Restore FDC table
443 .patch: mov si,bailmsg
444 call writestr ; Returns with AL = 0
446 int 16h ; Wait for keypress
447 int 19h ; And try once more to boot...
448 .norge: jmp short .norge ; If int 19h returned; this is the end
452 ; writestr: write a null-terminated string to the console
453 ; This assumes we're on page 0. This is only used for early
454 ; messages, so it should be OK.
460 mov ah,0Eh ; Write to screen as TTY
461 mov bx,0007h ; Attribute
467 ; xint13: wrapper for int 13h which will retry 6 times and then die,
468 ; AND save all registers except BP
480 jmp strict near kaboom ; Patched
484 ; getonesec: get one disk sector
487 mov bp,1 ; One sector
491 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
492 ; number in EAX into the buffer at ES:BX. We try to optimize
493 ; by loading up to a whole track at a time, but the user
494 ; is responsible for not crossing a 64K boundary.
495 ; (Yes, BP is weird for a count, but it was available...)
497 ; On return, BX points to the first byte after the transferred
500 ; This routine assumes CS == DS, and trashes most registers.
502 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
503 ; that is dead from that point; this saves space. However, please keep
504 ; the order to dst,src to keep things sane.
507 jmp strict short getlinsec_cbios ; This is patched
512 ; getlinsec implementation for EBIOS (EDD)
515 mov si,dapa ; Load up the DAPA
520 push bp ; Sectors left
521 call maxtrans ; Enforce maximum transfer size
525 mov ah,42h ; Extended Read
528 movzx eax,word [si+2] ; Sectors we read
529 add [si+8],eax ; Advance sector pointer
530 sub bp,ax ; Sectors left
531 shl ax,9 ; 512-byte sectors
532 add [si+4],ax ; Advance buffer pointer
535 mov eax,[si+8] ; Next sector
536 mov bx,[si+4] ; Buffer pointer
542 ; getlinsec implementation for legacy CBIOS
550 movzx esi,word [bsSecPerTrack]
551 movzx edi,word [bsHeads]
553 ; Dividing by sectors to get (track,sector): we may have
554 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
556 xor edx,edx ; Zero-extend LBA to 64 bits
559 xchg cx,dx ; CX <- sector index (0-based)
562 div edi ; Convert track to head/cyl
564 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
565 ; BP = sectors to transfer, SI = bsSecPerTrack,
566 ; ES:BX = data target
569 call maxtrans ; Enforce maximum transfer size
571 ; Must not cross track boundaries, so BP <= SI-CX
578 shl ah,6 ; Because IBM was STOOPID
579 ; and thought 8 bits were enough
580 ; then thought 10 bits were enough...
581 inc cx ; Sector numbers are 1-based, sigh
586 xchg ax,bp ; Sector to transfer count
587 mov ah,02h ; Read sectors
590 shl ax,9 ; Convert sectors in AL to bytes in AX
601 ; Truncate BP to MaxTransfer
610 ; Error message on failure
612 bailmsg: db 'Boot failed', 0Dh, 0Ah, 0
615 ; EBIOS disk address packet
620 .count: dw 0 ; Block count
621 .off: dw 0 ; Offset of buffer
622 .seg: dw 0 ; Segment of buffer
623 .lba: dd 0 ; LBA (LSW)
628 bs_checkpt_off equ ($-$$)
630 %if bs_checkpt_off > 1F8h
631 %error "Boot sector overflow"
637 FirstSector dd 0xDEADBEEF ; Location of sector 1
638 MaxTransfer dw 0x007F ; Max transfer size
639 bootsignature dw 0AA55h
642 ; ===========================================================================
644 ; ===========================================================================
645 ; Start of LDLINUX.SYS
646 ; ===========================================================================
650 syslinux_banner db 0Dh, 0Ah
656 db version_str, ' ', date, ' ', 0
657 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
660 ldlinux_magic dd LDLINUX_MAGIC
664 ; This area is patched by the installer. It is found by looking for
665 ; LDLINUX_MAGIC, plus 4 bytes.
668 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
669 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
670 CheckSum dd 0 ; Checksum starting at ldlinux_sys
671 ; value = LDLINUX_MAGIC - [sum of dwords]
673 ; Space for up to 64 sectors, the theoretical maximum
674 SectorPtrs times 64 dd 0
678 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
679 ; instead of 0000:7C00 and the like. We don't want to add anything
680 ; more to the boot sector, so it is written to not assume a fixed
681 ; value in CS, but we don't want to deal with that anymore from now
688 ; Tell the user we got this far
690 mov si,syslinux_banner
694 ; Patch disk error handling
696 mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3)
699 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
700 ; sector again, though.
704 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
710 lodsd ; First sector of this chunk
718 inc edx ; Next linear sector
719 cmp [esi],edx ; Does it match
720 jnz .chunk_ready ; If not, this is it
721 inc esi ; If so, add sector to chunk
722 jmp short .make_chunk
731 ; All loaded up, verify that we got what we needed.
732 ; Note: the checksum field is embedded in the checksum region, so
733 ; by the time we get to the end it should all cancel out.
738 mov edx,-LDLINUX_MAGIC
744 and edx,edx ; Should be zero
745 jz all_read ; We're cool, go for it!
748 ; Uh-oh, something went bad...
750 mov si,checksumerr_msg
755 ; -----------------------------------------------------------------------------
756 ; Subroutines that have to be in the first sector
757 ; -----------------------------------------------------------------------------
760 ; getlinsecsr: save registers, call getlinsec, restore registers
768 ; This routine captures disk errors, and tries to decide if it is
769 ; time to reduce the transfer size.
774 shr al,1 ; Try reducing the transfer size
776 jz kaboom ; If we can't, we're dead...
777 jmp xint13 ; Try again
788 ; Checksum error message
790 checksumerr_msg db 'Load error - ', 0 ; Boot failed appended
797 cmp word [Debug_Magic],0D00Dh
802 rl_checkpt equ $ ; Must be <= 8000h
804 rl_checkpt_off equ ($-$$)
806 %if rl_checkpt_off > 400h
807 %error "Sector 1 overflow"
811 ; ----------------------------------------------------------------------------
812 ; End of code and data that have to be in the first sector
813 ; ----------------------------------------------------------------------------
817 ; Let the user (and programmer!) know we got this far. This used to be
818 ; in Sector 1, but makes a lot more sense here.
825 ; Insane hack to expand the superblock to dwords
829 mov es,ax ; INT 13:08 destroys ES
832 mov cx,superinfo_size
836 stosd ; Store expanded word
838 stosd ; Store expanded byte
841 ; How big is a cluster, really? Also figure out how many clusters
842 ; will fit in the trackbuf, and how many sectors and bytes that is
844 ; FIX THIS: We shouldn't rely on integral sectors in the trackbuf
847 mov edi,[bxBytesPerSec] ; Used a lot below
848 mov eax,[SecPerClust]
849 mov si,ax ; Also used a lot
851 mov [ClustSize],eax ; Bytes/cluster
853 mov ax,trackbufsize ; High bit 0
856 mov [BufSafe],ax ; # of cluster in trackbuf
860 mov [BufSafeBytes],ax
861 add ax,getcbuf ; Size of getcbuf is the same
862 mov [EndOfGetCBuf],ax ; as for trackbuf
865 ; Compute some information about this filesystem.
868 ; First, generate the map of regions
873 mov edx,[bsHugeSectors]
875 mov [TotalSectors],edx
877 mov eax,[bsHidden] ; Hidden sectors aren't included
881 add eax,[bxResSectors]
882 mov [FAT],eax ; Beginning of FAT
886 mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
890 mov [RootDirArea],eax ; Beginning of root directory
891 mov [RootDir],eax ; For FAT12/16 == root dir location
893 mov edx,[bxRootDirEnts]
896 mov [RootDirSize],edx
898 mov [DataArea],eax ; Beginning of data area
900 ; Next, generate a cluster size shift count and mask
901 mov eax,[bxSecPerClust]
906 mov [ClustByteShift],cl
915 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
920 shr eax,cl ; cl == ClustShift
921 mov cl,nextcluster_fat12-(nextcluster+2)
922 cmp eax,4085 ; FAT12 limit
924 mov cl,nextcluster_fat16-(nextcluster+2)
925 cmp eax,65525 ; FAT16 limit
928 ; FAT32, root directory is a cluster chain
931 mov eax,[bootsec+44] ; Root directory cluster
936 mov cl,nextcluster_fat28-(nextcluster+2)
938 mov byte [nextcluster+1],cl
941 ; Common initialization code
943 %include "cpuinit.inc"
946 ; Initialization that does not need to go into the any of the pre-load
949 ; Now set up screen parameters
952 ; Wipe the F-key area
955 mov cx,10*(1 << FILENAME_MAX_LG2)
959 ; Now, everything is "up and running"... patch kaboom for more
960 ; verbosity and using the full screen system
963 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
966 ; Compute some parameters that depend on cluster size
970 inc dx ; DX:AX <- 64K
972 mov [ClustPerMoby],eax ; Clusters/64K
975 ; Now we're all set to start with our *real* business. First load the
976 ; configuration file (if any) and parse it.
978 ; In previous versions I avoided using 32-bit registers because of a
979 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
980 ; random. I figure, though, that if there are any of those still left
981 ; they probably won't be trying to install Linux on them...
983 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
984 ; to take'm out. In fact, we may want to put them back if we're going
985 ; to boot ELKS at some point.
987 mov si,linuxauto_cmd ; Default command: "linux auto"
992 mov di,KbdMap ; Default keymap 1:1
1000 ; Load configuration file
1007 ; Now we have the config file open. Parse the config file and
1008 ; run the user interface.
1013 ; Linux kernel loading code is common.
1015 %include "runkernel.inc"
1018 ; COMBOOT-loading code
1020 %include "comboot.inc"
1021 %include "com32.inc"
1022 %include "cmdline.inc"
1025 ; Boot sector loading code
1027 %include "bootsect.inc"
1030 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
1041 ac_kill: mov si,aborted_msg
1044 ; abort_load: Called by various routines which wants to print a fatal
1045 ; error message and return to the command prompt. Since this
1046 ; may happen at just about any stage of the boot process, assume
1047 ; our state is messed up, and just reset the segment registers
1048 ; and the stack forcibly.
1050 ; SI = offset (in _text) of error message to print
1053 mov ax,cs ; Restore CS = DS = ES
1057 mov sp,StackBuf-2*3 ; Reset stack
1058 mov ss,ax ; Just in case...
1060 call cwritestr ; Expects SI -> error msg
1061 al_ok: jmp enter_command ; Return to command prompt
1063 ; End of abort_check
1070 ; Search the root directory for a pre-mangled filename in DS:DI.
1072 ; NOTE: This file considers finding a zero-length file an
1073 ; error. This is so we don't have to deal with that special
1074 ; case elsewhere in the program (most loops have the test
1079 ; SI = cluster # for the first cluster
1080 ; DX:AX = file length in bytes
1087 mov ax,[bsRootDirEnts]
1089 mov ax,[RootDirSize]
1090 mov [DirBlocksLeft],ax
1093 movzx ebp,word [DirBlocksLeft]
1100 sub [DirBlocksLeft],bp
1102 mov ax,[bsBytesPerSec]
1105 mov [EndofDirSec],ax ; End of loaded
1110 dir_test_name: cmp byte [si],0 ; Directory high water mark
1111 je dir_return ; Failed
1112 test byte [si+11],18h ; Check it really is a file
1116 mov cx,11 ; Filename = 11 bytes
1121 dir_not_this: add si,byte 32
1122 dec word [DirScanCtr]
1123 jz dir_return ; Out of it...
1124 cmp si,[EndofDirSec]
1126 add eax,ebp ; Increment linear sector number
1127 jmp short scan_group
1129 mov ax,[si+28] ; Length of file
1131 mov si,[si+26] ; Cluster pointer
1133 or bx,dx ; Sets ZF iff DX:AX is zero
1139 ; writechr: Write a single character in AL to the console without
1140 ; mangling any registers; handle video pages correctly.
1143 call write_serial ; write to serial port if needed
1147 mov bl,07h ; attribute
1148 mov bh,[cs:BIOS_page] ; current page
1156 ; kaboom2: once everything is loaded, replace the part of kaboom
1157 ; starting with "kaboom.patch" with this part
1160 mov si,err_bootfailed
1164 int 19h ; And try once more to boot...
1165 .norge: jmp short .norge ; If int 19h returned; this is the end
1168 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
1169 ; to by ES:DI; ends on encountering any whitespace
1173 mov cx,11 ; # of bytes to write
1176 cmp al,' ' ; If control or space, end
1178 cmp al,'.' ; Period -> space-fill
1185 jmp short mn_not_lower
1186 mn_is_period: mov al,' ' ; We need to space-fill
1187 mn_period_loop: cmp cx,3 ; If <= 3 characters left
1188 jbe mn_loop ; Just ignore it
1189 stosb ; Otherwise, write a period
1190 loop mn_period_loop ; Dec CX and (always) jump
1191 mn_not_uslower: cmp al,ucase_low
1195 mov bx,ucase_tab-ucase_low
1198 loop mn_loop ; Don't continue if too long
1200 mov al,' ' ; Space-fill name
1201 rep stosb ; Doesn't do anything if CX=0
1205 ; Upper-case table for extended characters; this is technically code page 865,
1206 ; but code page 437 users will probably not miss not being able to use the
1207 ; cent sign in kernel images too much :-)
1209 ; The table only covers the range 129 to 164; the rest we can deal with.
1213 ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1214 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1215 db 157, 156, 157, 158, 159, 'AIOU', 165
1218 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1219 ; filename to the conventional representation. This is needed
1220 ; for the BOOT_IMAGE= parameter for the kernel.
1221 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1222 ; known to be shorter.
1224 ; DS:SI -> input mangled file name
1225 ; ES:DI -> output buffer
1227 ; On return, DI points to the first byte after the output name,
1228 ; which is set to a null byte.
1231 push si ; Save pointer to original name
1239 mov bp,di ; Position of last nonblank+1
1240 un_cb_space: loop un_copy_body
1242 mov al,'.' ; Don't save
1251 un_ce_space: loop un_copy_ext
1258 ; lower_case: Lower case a character in AL
1267 lc_1: cmp al,lcase_low
1272 mov bx,lcase_tab-lcase_low
1278 ; getfssec_edx: Get multiple sectors from a file
1280 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1281 ; and will correct the situation if it does, UNLESS *sectors* cross
1285 ; EDX -> Current sector number
1286 ; CX -> Sector count (0FFFFh = until end of file)
1287 ; Must not exceed the ES segment
1288 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1289 ; All arguments are advanced to reflect data read.
1295 xor ebp,ebp ; Fragment sector count
1302 add ax,bx ; Now DI = how far into 64K block we are
1303 neg ax ; Bytes left in 64K block
1304 shr ax,9 ; Sectors left in 64K block
1306 jnb .do_read ; Unless there is at least 1 more sector room...
1307 lea eax,[edx+1] ; Linearly next sector
1315 lea eax,[eax+ebp-1] ; This is the last sector actually read
1317 add bx,bp ; Adjust buffer pointer
1333 ; getfssec: Get multiple sectors from a file
1335 ; Same as above, except SI is a pointer to a dword with the current sector.
1338 ; DS:SI -> Pointer to current sector number
1339 ; CX -> Sector count (0FFFFh = until end of file)
1340 ; Must not exceed the ES segment
1341 ; Returns CF=1 on EOF (not necessarily error)
1342 ; All arguments are advanced to reflect data read.
1353 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1354 ; pointed at in the FAT tables. CF=0 on return if end of file.
1357 jmp strict short nextcluster_fat28 ; This gets patched
1395 ; FAT16 decoding routine.
1402 shr eax,SECTOR_SHIFT-1
1407 movzx edi,word [gs:si+bx]
1414 ; FAT28 ("FAT32") decoding routine.
1421 shr eax,SECTOR_SHIFT-2
1427 mov edi,dword [gs:si+bx]
1428 and edi,0FFFFFFFh ; 28 bits only
1436 ; nextsector: Given a sector in EAX on input, return the next sector
1437 ; of the same filesystem object, which may be the root
1438 ; directory or a cluster chain. Returns EOF.
1458 test edi,[ClustMask]
1461 ; It's not the final sector in a cluster
1466 push gs ; nextcluster trashes gs
1473 ; Now EDI contains the cluster number
1476 jc .exit ; There isn't anything else...
1478 ; New cluster number now in EDI
1480 shl edi,cl ; CF <- 0, unless something is very wrong
1491 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1492 ; and return a pointer in GS:SI, loading it if needed.
1497 add eax,[bsHidden] ; Hidden sectors
1498 add eax,[bxResSectors] ; Reserved sectors
1502 ; getcachesector: Check for a particular sector (EAX) in the sector cache,
1503 ; and if it is already there, return a pointer in GS:SI
1504 ; otherwise load it and return said pointer.
1512 mov si,CachePtrs ; Sector cache pointers
1513 mov cx,65536/SECTOR_SIZE
1514 repne scasd ; Do we have it?
1516 ; We have it; get the pointer
1518 shl si,SECTOR_SHIFT-2
1522 ; Need to load it. Highly inefficient cache replacement
1523 ; algorithm: Least Recently Written (LRW)
1528 mov bx,[NextCacheSlot]
1530 and bx,(1 << (16-SECTOR_SHIFT))-1
1531 mov [NextCacheSlot],bx
1533 mov [CachePtrs+bx],eax
1534 shl bx,SECTOR_SHIFT-2
1544 ; -----------------------------------------------------------------------------
1546 ; -----------------------------------------------------------------------------
1548 %include "getc.inc" ; getc et al
1549 %include "conio.inc" ; Console I/O
1550 %include "writestr.inc" ; String output
1551 %include "parseconfig.inc" ; High-level config file handling
1552 %include "parsecmd.inc" ; Low-level config file handling
1553 %include "bcopy32.inc" ; 32-bit bcopy
1554 %include "loadhigh.inc" ; Load a file into high memory
1555 %include "font.inc" ; VGA font stuff
1556 %include "graphics.inc" ; VGA graphics
1557 %include "highmem.inc" ; High memory sizing
1558 %include "strcpy.inc" ; strcpy()
1560 ; -----------------------------------------------------------------------------
1561 ; Begin data section
1562 ; -----------------------------------------------------------------------------
1565 ; Lower-case table for codepage 865
1569 lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
1570 db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
1571 db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
1572 db 161, 162, 163, 164, 164
1574 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1576 boot_prompt db 'boot: ', 0
1577 wipe_char db BS, ' ', BS, 0
1578 err_notfound db 'Could not find kernel image: ',0
1579 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1580 err_noram db 'It appears your computer has less than '
1582 db 'K of low ("DOS")'
1584 db 'RAM. Linux needs at least this amount to boot. If you get'
1586 db 'this message in error, hold down the Ctrl key while'
1588 db 'booting, and I will take your word for it.', CR, LF, 0
1589 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1590 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1591 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1592 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1593 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1594 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1596 err_notdos db ': attempted DOS system call', CR, LF, 0
1597 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1598 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1599 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1600 db 'a key to continue.', CR, LF, 0
1601 ready_msg db 'Ready.', CR, LF, 0
1602 crlfloading_msg db CR, LF
1603 loading_msg db 'Loading ', 0
1606 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1609 crff_msg db CR, FF, 0
1610 syslinux_cfg db 'SYSLINUXCFG' ; Mangled form
1611 ConfigName db 'syslinux.cfg',0 ; Unmangled form
1613 manifest db 'MANIFEST '
1616 ; Command line options we'd like to take a look at
1618 ; mem= and vga= are handled as normal 32-bit integer values
1619 initrd_cmd db 'initrd='
1620 initrd_cmd_len equ 7
1623 ; Config file keyword table
1625 %include "keywords.inc"
1628 ; Extensions to search for (in *forward* order).
1630 exten_table: db 'CBT',0 ; COMBOOT (specific)
1631 db 'BSS',0 ; Boot Sector (add superblock)
1632 db 'BS ',0 ; Boot Sector
1633 db 'COM',0 ; COMBOOT (same as DOS)
1636 dd 0, 0 ; Need 8 null bytes here
1639 ; Misc initialized (data) variables
1641 %ifdef debug ; This code for debugging only
1642 debug_magic dw 0D00Dh ; Debug code sentinel
1644 AppendLen dw 0 ; Bytes in append= command
1645 OntimeoutLen dw 0 ; Bytes in ontimeout command
1646 OnerrorLen dw 0 ; Bytes in onerror command
1647 KbdTimeOut dw 0 ; Keyboard timeout (if any)
1648 CmdLinePtr dw cmd_line_here ; Command line advancing pointer
1650 initrd_ptr dw 0 ; Initial ramdisk pointer/flag
1651 VKernelCtr dw 0 ; Number of registered vkernels
1652 ForcePrompt dw 0 ; Force prompt
1653 AllowImplicit dw 1 ; Allow implicit kernels
1654 AllowOptions dw 1 ; User-specified options allowed
1655 SerialPort dw 0 ; Serial port base (or 0 for no serial port)
1656 VGAFontSize dw 16 ; Defaults to 16 byte font
1657 UserFont db 0 ; Using a user-specified font
1658 ScrollAttribute db 07h ; White on black (for text mode)
1661 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1662 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1663 BufSafeBytes dw trackbufsize ; = how many bytes?
1664 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1666 %if ( trackbufsize % SECTOR_SIZE ) != 0
1667 %error trackbufsize must be a multiple of SECTOR_SIZE
1671 ; Stuff for the command line; we do some trickery here with equ to avoid
1672 ; tons of zeros appended to our file and wasting space
1674 linuxauto_cmd db 'linux auto',0
1675 linuxauto_len equ $-linuxauto_cmd
1676 boot_image db 'BOOT_IMAGE='
1677 boot_image_len equ $-boot_image
1679 align 4, db 0 ; Pad out any unfinished dword
1681 ldlinux_len equ $-ldlinux_magic
1683 ; VGA font buffer at the end of memory (so loading a font works even
1684 ; in graphics mode.)
1685 vgafontbuf equ 0E000h
1687 ; This is a compile-time assert that we didn't run out of space
1689 %if (ldlinux_end-bootsec+7C00h) > vgafontbuf
1690 %error "Out of memory, better reorganize something..."