1 ; -*- fundamental -*- (asm-mode sucks)
3 ; ****************************************************************************
7 ; A program to boot Linux kernels off an ext2/ext3 filesystem.
9 ; Copyright (C) 1994-2004 H. Peter Anvin
11 ; This program is free software; you can redistribute it and/or modify
12 ; it under the terms of the GNU General Public License as published by
13 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
14 ; Boston MA 02111-1307, USA; either version 2 of the License, or
15 ; (at your option) any later version; incorporated herein by reference.
17 ; ****************************************************************************
24 %include "tracers.inc"
26 %include "ext2_fs.inc"
29 ; Some semi-configurable constants... change on your own risk.
32 FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
33 FILENAME_MAX equ (1 << FILENAME_MAX) ; Max mangled filename size
34 NULLFILE equ ' ' ; First char space == null filename
35 retry_count equ 6 ; How patient are we with the disk?
36 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
37 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
39 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
40 MAX_OPEN equ (1 << MAX_OPEN_LG2)
43 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
46 ; This is what we need to do when idle
56 ; The following structure is used for "virtual kernels"; i.e. LILO-style
57 ; option labels. The options we permit here are `kernel' and `append
58 ; Since there is no room in the bottom 64K for all of these, we
59 ; stick them at vk_seg:0000 and copy them down before we need them.
62 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
63 vk_rname: resb FILENAME_MAX ; Real name
66 vk_append: resb max_cmd_len+1 ; Command line
68 vk_end: equ $ ; Should be <= vk_size
72 ; Segment assignments in the bottom 640K
73 ; Stick to the low 512K in case we're using something like M-systems flash
74 ; which load a driver into low RAM (evil!!)
76 ; 0000h - main code/data segment (and BIOS segment)
78 real_mode_seg equ 4000h
79 cache_seg equ 3000h ; 64K area for metadata cache
80 vk_seg equ 2000h ; Virtual kernels
81 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
82 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
85 ; File structure. This holds the information for each currently open file.
88 file_left resd 1 ; Number of sectors left (0 = free)
89 file_sector resd 1 ; Next linear sector to read
90 file_in_sec resd 1 ; Sector where inode lives
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 section .bss start=BSS_START
110 trackbufsize equ 8192
111 trackbuf resb trackbufsize ; Track buffer goes here
112 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 EndSector resd 1 ; Location of filesystem end
127 ClustSize resd 1 ; Bytes/cluster
128 ClustMask resd 1 ; Sectors/cluster - 1
129 CopySuper resb 1 ; Distinguish .bs versus .bss
130 DriveNumber resb 1 ; BIOS drive number
131 ClustShift resb 1 ; Shift count for sectors/cluster
132 ClustByteShift resb 1 ; Shift count for bytes/cluster
134 alignb open_file_t_size
135 Files resb MAX_OPEN*open_file_t_size
138 ; Constants for the xfer_buf_seg
140 ; The xfer_buf_seg is also used to store message file buffers. We
141 ; need two trackbuffers (text and graphics), plus a work buffer
142 ; for the graphics decompressor.
144 xbs_textbuf equ 0 ; Also hard-coded, do not change
145 xbs_vgabuf equ trackbufsize
146 xbs_vgatmpbuf equ 2*trackbufsize
152 ; Some of the things that have to be saved very early are saved
153 ; "close" to the initial stack pointer offset, in order to
154 ; reduce the code size...
156 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
157 PartInfo equ StackBuf ; Saved partition table entry
158 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
159 OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
162 ; Primary entry point. Tempting as though it may be, we can't put the
163 ; initial "cli" here; the jmp opcode in the first byte is part of the
164 ; "magic number" (using the term very loosely) for the DOS superblock.
167 jmp short start ; 2 bytes
170 ; "Superblock" follows -- it's in the boot sector, so it's already
171 ; loaded and ready for us
173 bsOemName db 'EXTLINUX' ; The SYS command sets this, so...
175 ; These are the fields we actually care about. We end up expanding them
176 ; all to dword size early in the code, so generate labels for both
177 ; the expanded and unexpanded versions.
180 bx %+ %1 equ SuperInfo+($-superblock)*8+4
185 bx %+ %1 equ SuperInfo+($-superblock)*8
190 bx %+ %1 equ $ ; no expansion for dwords
205 superinfo_size equ ($-superblock)-1 ; How much to expand
209 ; This is as far as FAT12/16 and FAT32 are consistent
211 zb 54 ; FAT12/16 need 26 more bytes,
212 ; FAT32 need 54 more bytes
213 superblock_len equ $-superblock
215 SecPerClust equ bxSecPerClust
217 ; Note we don't check the constraints above now; we did that at install
221 cli ; No interrupts yet, please
228 mov sp,StackBuf ; Just below BSS
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
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+1],getlinsec_ebios-(getlinsec+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],LDLINUX_MAGIC
343 cmp dword [ldlinux_magic+4],HEXDATE
350 ; kaboom: write a message and bail out.
355 mov sp,StackBuf-4 ; Reset stack
356 mov ds,si ; Reset data segment
357 pop dword [fdctab] ; Restore FDC table
358 .patch: mov si,bailmsg
359 call writestr ; Returns with AL = 0
361 int 16h ; Wait for keypress
362 int 19h ; And try once more to boot...
363 .norge: jmp short .norge ; If int 19h returned; this is the end
367 ; writestr: write a null-terminated string to the console
368 ; This assumes we're on page 0. This is only used for early
369 ; messages, so it should be OK.
375 mov ah,0Eh ; Write to screen as TTY
376 mov bx,0007h ; Attribute
382 ; xint13: wrapper for int 13h which will retry 6 times and then die,
383 ; AND save all registers except BP
395 jmp strict near kaboom ; Patched
399 ; getonesec: get one disk sector
402 mov bp,1 ; One sector
406 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
407 ; number in EAX into the buffer at ES:BX. We try to optimize
408 ; by loading up to a whole track at a time, but the user
409 ; is responsible for not crossing a 64K boundary.
410 ; (Yes, BP is weird for a count, but it was available...)
412 ; On return, BX points to the first byte after the transferred
415 ; This routine assumes CS == DS, and trashes most registers.
417 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
418 ; that is dead from that point; this saves space. However, please keep
419 ; the order to dst,src to keep things sane.
422 jmp strict short getlinsec_cbios ; This is patched
427 ; getlinsec implementation for EBIOS (EDD)
430 mov si,dapa ; Load up the DAPA
435 push bp ; Sectors left
436 call maxtrans ; Enforce maximum transfer size
440 mov ah,42h ; Extended Read
443 movzx eax,word [si+2] ; Sectors we read
444 add [si+8],eax ; Advance sector pointer
445 sub bp,ax ; Sectors left
446 shl ax,9 ; 512-byte sectors
447 add [si+4],ax ; Advance buffer pointer
450 mov eax,[si+8] ; Next sector
451 mov bx,[si+4] ; Buffer pointer
457 ; getlinsec implementation for legacy CBIOS
465 movzx esi,word [bsSecPerTrack]
466 movzx edi,word [bsHeads]
468 ; Dividing by sectors to get (track,sector): we may have
469 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
471 xor edx,edx ; Zero-extend LBA to 64 bits
474 xchg cx,dx ; CX <- sector index (0-based)
477 div edi ; Convert track to head/cyl
479 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
480 ; BP = sectors to transfer, SI = bsSecPerTrack,
481 ; ES:BX = data target
484 call maxtrans ; Enforce maximum transfer size
486 ; Must not cross track boundaries, so BP <= SI-CX
493 shl ah,6 ; Because IBM was STOOPID
494 ; and thought 8 bits were enough
495 ; then thought 10 bits were enough...
496 inc cx ; Sector numbers are 1-based, sigh
501 xchg ax,bp ; Sector to transfer count
502 mov ah,02h ; Read sectors
505 shl ax,9 ; Convert sectors in AL to bytes in AX
516 ; Truncate BP to MaxTransfer
525 ; Error message on failure
527 bailmsg: db 'Boot failed', 0Dh, 0Ah, 0
530 ; EBIOS disk address packet
535 .count: dw 0 ; Block count
536 .off: dw 0 ; Offset of buffer
537 .seg: dw 0 ; Segment of buffer
538 .lba: dd 0 ; LBA (LSW)
543 bs_checkpt_off equ ($-$$)
545 %if bs_checkpt_off > 1F8h
546 %error "Boot sector overflow"
552 FirstSector dd 0xDEADBEEF ; Location of sector 1
553 MaxTransfer dw 0x007F ; Max transfer size
554 bootsignature dw 0AA55h
557 ; ===========================================================================
559 ; ===========================================================================
560 ; Start of LDLINUX.SYS
561 ; ===========================================================================
565 syslinux_banner db 0Dh, 0Ah
567 db version_str, ' ', date, ' ', 0
568 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
571 ldlinux_magic dd LDLINUX_MAGIC
575 ; This area is patched by the installer. It is found by looking for
576 ; LDLINUX_MAGIC, plus 8 bytes.
579 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
580 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
581 CheckSum dd 0 ; Checksum starting at ldlinux_sys
582 ; value = LDLINUX_MAGIC - [sum of dwords]
584 ; Space for up to 64 sectors, the theoretical maximum
585 SectorPtrs times 64 dd 0
589 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
590 ; instead of 0000:7C00 and the like. We don't want to add anything
591 ; more to the boot sector, so it is written to not assume a fixed
592 ; value in CS, but we don't want to deal with that anymore from now
599 ; Tell the user we got this far
601 mov si,syslinux_banner
605 ; Patch disk error handling
607 mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3)
610 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
611 ; sector again, though.
615 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
621 lodsd ; First sector of this chunk
629 inc edx ; Next linear sector
630 cmp [esi],edx ; Does it match
631 jnz .chunk_ready ; If not, this is it
632 add esi,4 ; If so, add sector to chunk
633 jmp short .make_chunk
644 ; All loaded up, verify that we got what we needed.
645 ; Note: the checksum field is embedded in the checksum region, so
646 ; by the time we get to the end it should all cancel out.
651 mov edx,-LDLINUX_MAGIC
657 and edx,edx ; Should be zero
658 jz all_read ; We're cool, go for it!
661 ; Uh-oh, something went bad...
663 mov si,checksumerr_msg
668 ; -----------------------------------------------------------------------------
669 ; Subroutines that have to be in the first sector
670 ; -----------------------------------------------------------------------------
673 ; getlinsecsr: save registers, call getlinsec, restore registers
681 ; This routine captures disk errors, and tries to decide if it is
682 ; time to reduce the transfer size.
687 shr al,1 ; Try reducing the transfer size
689 jz kaboom ; If we can't, we're dead...
690 jmp xint13 ; Try again
701 ; Checksum error message
703 checksumerr_msg db 'Load error - ', 0 ; Boot failed appended
710 cmp word [Debug_Magic],0D00Dh
715 rl_checkpt equ $ ; Must be <= 8000h
717 rl_checkpt_off equ ($-$$)
719 %if rl_checkpt_off > 400h
720 %error "Sector 1 overflow"
724 ; ----------------------------------------------------------------------------
725 ; End of code and data that have to be in the first sector
726 ; ----------------------------------------------------------------------------
730 ; Let the user (and programmer!) know we got this far. This used to be
731 ; in Sector 1, but makes a lot more sense here.
737 ; Insane hack to expand the DOS superblock to dwords
743 mov cx,superinfo_size
747 stosd ; Store expanded word
749 stosd ; Store expanded byte
753 ; Compute some information about this filesystem.
757 ; Common initialization code
759 %include "cpuinit.inc"
762 ; Clear Files structures
765 mov cx,(MAX_OPEN*open_file_t_size)/4
770 ; Initialize the metadata cache
775 ; Initialization that does not need to go into the any of the pre-load
778 ; Now set up screen parameters
781 ; Wipe the F-key area
784 mov cx,10*(1 << FILENAME_MAX_LG2)
788 ; Now, everything is "up and running"... patch kaboom for more
789 ; verbosity and using the full screen system
792 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
795 ; Now we're all set to start with our *real* business. First load the
796 ; configuration file (if any) and parse it.
798 ; In previous versions I avoided using 32-bit registers because of a
799 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
800 ; random. I figure, though, that if there are any of those still left
801 ; they probably won't be trying to install Linux on them...
803 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
804 ; to take'm out. In fact, we may want to put them back if we're going
805 ; to boot ELKS at some point.
807 mov si,linuxauto_cmd ; Default command: "linux auto"
812 mov di,KbdMap ; Default keymap 1:1
820 ; Load configuration file
827 ; Now we have the config file open. Parse the config file and
828 ; run the user interface.
833 ; Linux kernel loading code is common.
835 %include "runkernel.inc"
838 ; COMBOOT-loading code
840 %include "comboot.inc"
842 %include "cmdline.inc"
845 ; Boot sector loading code
847 %include "bootsect.inc"
850 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
861 ac_kill: mov si,aborted_msg
864 ; abort_load: Called by various routines which wants to print a fatal
865 ; error message and return to the command prompt. Since this
866 ; may happen at just about any stage of the boot process, assume
867 ; our state is messed up, and just reset the segment registers
868 ; and the stack forcibly.
870 ; SI = offset (in _text) of error message to print
873 mov ax,cs ; Restore CS = DS = ES
877 mov sp,StackBuf-2*3 ; Reset stack
878 mov ss,ax ; Just in case...
880 call cwritestr ; Expects SI -> error msg
881 al_ok: jmp enter_command ; Return to command prompt
889 ; allocate_file: Allocate a file structure
902 .check: cmp dword [bx], byte 0
904 add bx,open_file_t_size ; ZF = 0
906 ; ZF = 0 if we fell out of the loop
911 ; Open a file indicated by an inode number in EAX
913 ; NOTE: This file considers finding a zero-length file an
914 ; error. This is so we don't have to deal with that special
915 ; case elsewhere in the program (most loops have the test
921 ; DX:AX = EAX = file length in bytes
925 open_inode.allocate_failure:
931 jnz .allocate_failure
934 ; First, get the appropriate inode group and index
935 dec eax ; There is no inode 0
937 mov [bx+file_sector],edx
938 div dword [SuperBlock+s_inodes_per_group]
939 ; EAX = inode group; EDX = inode within group
942 ; Now, we need the block group descriptor.
943 ; To get that, we first need the relevant descriptor block.
945 shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
947 div dword [BlockSize]
948 ; eax = block #, edx = offset in block
949 add eax,dword [SuperBlock+s_first_data_block]
950 inc eax ; s_first_data_block+1
953 call getcachesec ; Get the group descriptor
955 mov esi,[gs:si+bg_inode_table] ; Get inode table block #
956 pop eax ; Get inode within group
957 movzx edx, word [SuperBlock+s_inode_size]
959 ; edx:eax = byte offset in inode table
960 div dword [BlockSize]
961 ; eax = block # versus inode table, edx = offset in block
963 shl eax,cl ; Turn into sector
967 mov [bx+file_in_sec],eax
970 mov [bx+file_in_off],dx
974 mov eax,[gs:si+i_size]
976 add eax,SECTOR_SIZE-1
978 mov [bx+file_left],eax
982 shr edx,16 ; 16-bitism, sigh
983 and eax,eax ; ZF clear unless zero-length file
989 ; Deallocates a file structure (pointer in SI)
993 mov dword [si],0 ; First dword == file_left
998 ; Search the root directory for a pre-mangled filename in DS:DI.
1000 ; NOTE: This file considers finding a zero-length file an
1001 ; error. This is so we don't have to deal with that special
1002 ; case elsewhere in the program (most loops have the test
1008 ; DX:AX = EAX = file length in bytes
1012 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
1015 mov eax,[CurrentDir]
1017 cmp byte [di],'/' ; Absolute filename?
1019 mov eax,EXT2_ROOT_INO
1023 ; At this point, EAX contains the directory inode,
1024 ; and DS:DI contains a pathname tail.
1030 mov cx,[SecPerBlock]
1033 pushf ; Save EOF flag
1035 cmp dword [bx+d_inode],0
1040 mov cx,[bx+d_name_len]
1048 add bx,[bx+d_rec_len]
1053 jnc .readdir ; There is more
1058 mov eax,[si+d_inode]
1061 je .finish ; It's a real file; done
1063 jne .nope ; False alarm
1065 ; It's a match, but it's a directory.
1068 pop si ; Adjust stack (di)
1069 pop si ; Adjust stack (flags)
1074 .finish: ; We found it; now we need to open the file
1075 call close ; Close directory
1076 pop si ; Adjust stack (di)
1077 pop si ; Adjust stack (flags)
1082 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1083 ; to by ES:DI; ends on encountering any whitespace.
1085 ; This verifies that a filename is < FILENAME_MAX characters,
1086 ; doesn't contain whitespace, zero-pads the output buffer,
1087 ; and removes redundant slashes,
1088 ; so "repe cmpsb" can do a compare, and the
1089 ; path-searching routine gets a bit of an easier job.
1091 ; FIX: we may want to support \-escapes here (and this would
1097 mov cx,FILENAME_MAX-1
1102 cmp al,' ' ; If control or space, end
1104 cmp al,ah ; Repeated slash?
1111 .mn_skip: loop .mn_loop
1113 cmp bx,di ; At the beginning of the buffer?
1115 cmp byte [di-1],'/' ; Terminal slash?
1117 .mn_kill: dec di ; If so, remove it
1121 inc cx ; At least one null byte
1122 xor ax,ax ; Zero-fill name
1128 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1129 ; filename to the conventional representation. This is needed
1130 ; for the BOOT_IMAGE= parameter for the kernel.
1131 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1132 ; known to be shorter.
1134 ; DS:SI -> input mangled file name
1135 ; ES:DI -> output buffer
1137 ; On return, DI points to the first byte after the output name,
1138 ; which is set to a null byte.
1140 unmangle_name: call strcpy
1141 dec di ; Point to final null byte
1145 ; writechr: Write a single character in AL to the console without
1146 ; mangling any registers; handle video pages correctly.
1149 call write_serial ; write to serial port if needed
1153 mov bl,07h ; attribute
1154 mov bh,[cs:BIOS_page] ; current page
1162 ; kaboom2: once everything is loaded, replace the part of kaboom
1163 ; starting with "kaboom.patch" with this part
1166 mov si,err_bootfailed
1170 int 19h ; And try once more to boot...
1171 .norge: jmp short .norge ; If int 19h returned; this is the end
1175 ; linsector: Convert a linear sector index in a file to a linear sector number
1176 ; EAX -> linear sector number
1177 ; DS:SI -> open_file_t
1179 ; Returns next sector number in EAX; CF on EOF (not an error!)
1192 shr eax,cl ; Convert to block number
1194 mov eax,[si+file_in_sec]
1196 call getcachesector ; Get inode
1197 add si,[bx+file_in_off] ; Get *our* inode
1199 lea ebx,[i_block+4*eax]
1200 cmp eax,EXT2_NDIR_BLOCKS
1202 mov ebx,[gs:si+i_block+4*EXT2_IND_BLOCK]
1203 sub eax,EXT2_NDIR_BLOCKS
1204 mov ebp,[PtrsPerBlk1]
1206 mov ebx,[gs:si+i_block+4*EXT2_DIND_BLOCK]
1208 mov ebp,[PtrsPerBlock2]
1211 mov ebx,[gs:si+i_block+4*EXT2_TIND_BLOCK]
1215 ; Triple indirect; eax contains the block no
1216 ; with respect to the start of the tind area;
1217 ; ebx contains the pointer to the tind block.
1219 div dword [PtrsPerBlock3]
1220 ; EAX = which dind block, EDX = block no in dind block
1222 shl ebx,cl ; Sector # for tind block
1224 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1228 shl bx,2 ; Convert to byte offset
1229 and bx,SECTOR_SIZE-1
1231 mov ebx,[gs:bx+si] ; Get the pointer
1232 mov eax,edx ; The int2 code wants the remainder...
1234 ; Double indirect; eax contains the block no
1235 ; with respect to the start of the dind area;
1236 ; ebx contains the pointer to the dind block.
1238 div dword [PtrsPerBlock2]
1239 ; EAX = which dind block, EDX = block no in dind block
1241 shl ebx,cl ; Sector # for tind block
1243 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1247 shl bx,2 ; Convert to byte offset
1248 and bx,SECTOR_SIZE-1
1250 mov ebx,[gs:bx+si] ; Get the pointer
1251 mov eax,edx ; The ind1 code wants the remainder...
1253 ; Single indirect; eax contains the block no
1254 ; with respect to the start of the ind area;
1255 ; ebx contains the pointer to the ind block.
1257 div dword [PtrsPerBlock1]
1258 ; EAX = which dind block, EDX = block no in dind block
1260 shl ebx,cl ; Sector # for tind block
1262 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1266 shl bx,2 ; Convert to byte offset
1267 and bx,SECTOR_SIZE-1
1270 mov ebx,[gs:bx+si] ; Get the pointer
1272 pop eax ; Get the sector index again
1273 shl ebx,cl ; Convert block number to sector
1274 and eax,[ClustMask] ; Add offset within block
1287 ; getfssec: Get multiple sectors from a file
1289 ; Same as above, except SI is a pointer to a open_file_t
1292 ; DS:SI -> Pointer to open_file_t
1293 ; CX -> Sector count (0FFFFh = until end of file)
1294 ; Must not exceed the ES segment
1295 ; Returns CF=1 on EOF (not necessarily error)
1296 ; All arguments are advanced to reflect data read.
1304 mov eax,[si] ; Current start index
1307 push eax ; Fragment start sector
1309 xor ebp,ebp ; Fragment sector count
1317 add ax,bx ; Now DI = how far into 64K block we are
1318 not ax ; Bytes left in 64K block
1320 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1322 jnb .do_read ; Unless there is at least 1 more sector room...
1323 inc ebx ; Sector index
1324 inc edx ; Linearly next sector
1331 pop eax ; Linear start sector
1333 lea eax,[eax+ebp-1] ; This is the last sector actually read
1335 add bx,bp ; Adjust buffer pointer
1354 ; -----------------------------------------------------------------------------
1356 ; -----------------------------------------------------------------------------
1358 %include "getc.inc" ; getc et al
1359 %include "conio.inc" ; Console I/O
1360 %include "writestr.inc" ; String output
1361 %include "parseconfig.inc" ; High-level config file handling
1362 %include "parsecmd.inc" ; Low-level config file handling
1363 %include "bcopy32.inc" ; 32-bit bcopy
1364 %include "loadhigh.inc" ; Load a file into high memory
1365 %include "font.inc" ; VGA font stuff
1366 %include "graphics.inc" ; VGA graphics
1367 %include "highmem.inc" ; High memory sizing
1368 %include "strcpy.inc" ; strcpy()
1369 %include "cache.inc"
1371 ; -----------------------------------------------------------------------------
1372 ; Begin data section
1373 ; -----------------------------------------------------------------------------
1376 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1378 boot_prompt db 'boot: ', 0
1379 wipe_char db BS, ' ', BS, 0
1380 err_notfound db 'Could not find kernel image: ',0
1381 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1382 err_noram db 'It appears your computer has less than '
1384 db 'K of low ("DOS")'
1386 db 'RAM. Linux needs at least this amount to boot. If you get'
1388 db 'this message in error, hold down the Ctrl key while'
1390 db 'booting, and I will take your word for it.', CR, LF, 0
1391 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1392 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1393 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1394 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1395 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1396 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1398 err_notdos db ': attempted DOS system call', CR, LF, 0
1399 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1400 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1401 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1402 db 'a key to continue.', CR, LF, 0
1403 ready_msg db 'Ready.', CR, LF, 0
1404 crlfloading_msg db CR, LF
1405 loading_msg db 'Loading ', 0
1408 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1411 crff_msg db CR, FF, 0
1412 ConfigName db 'syslinux.cfg',0 ; Unmangled form
1415 ; Command line options we'd like to take a look at
1417 ; mem= and vga= are handled as normal 32-bit integer values
1418 initrd_cmd db 'initrd='
1419 initrd_cmd_len equ 7
1422 ; Config file keyword table
1424 %include "keywords.inc"
1427 ; Extensions to search for (in *forward* order).
1430 exten_table: db '.cbt' ; COMBOOT (specific)
1431 db '.img' ; Disk image
1432 db '.bs', 0 ; Boot sector
1433 db '.com' ; COMBOOT (same as DOS)
1436 dd 0, 0 ; Need 8 null bytes here
1439 ; Misc initialized (data) variables
1441 %ifdef debug ; This code for debugging only
1442 debug_magic dw 0D00Dh ; Debug code sentinel
1446 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1447 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1448 BufSafeBytes dw trackbufsize ; = how many bytes?
1449 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1451 %if ( trackbufsize % SECTOR_SIZE ) != 0
1452 %error trackbufsize must be a multiple of SECTOR_SIZE
1455 align 4, db 0 ; Pad out any unfinished dword