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
115 SuperBlock resb 1024 ; ext2 superblock
116 SuperInfo resd 16 ; DOS superblock expanded
117 ClustSize resd 1 ; Bytes/cluster ("block")
118 SecPerClust resd 1 ; Sectors/cluster
119 ClustMask resd 1 ; Sectors/cluster - 1
120 PtrsPerBlock1 resd 1 ; Pointers/cluster
121 PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2
122 PtrsPerBlock3 resd 1 ; (Pointers/cluster)^3
123 DriveNumber resb 1 ; BIOS drive number
124 ClustShift resb 1 ; Shift count for sectors/cluster
125 ClustByteShift resb 1 ; Shift count for bytes/cluster
127 alignb open_file_t_size
128 Files resb MAX_OPEN*open_file_t_size
131 ; Constants for the xfer_buf_seg
133 ; The xfer_buf_seg is also used to store message file buffers. We
134 ; need two trackbuffers (text and graphics), plus a work buffer
135 ; for the graphics decompressor.
137 xbs_textbuf equ 0 ; Also hard-coded, do not change
138 xbs_vgabuf equ trackbufsize
139 xbs_vgatmpbuf equ 2*trackbufsize
145 ; Some of the things that have to be saved very early are saved
146 ; "close" to the initial stack pointer offset, in order to
147 ; reduce the code size...
149 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
150 PartInfo equ StackBuf ; Saved partition table entry
151 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
152 OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
155 ; Primary entry point. Tempting as though it may be, we can't put the
156 ; initial "cli" here; the jmp opcode in the first byte is part of the
157 ; "magic number" (using the term very loosely) for the DOS superblock.
160 jmp short start ; 2 bytes
163 ; "Superblock" follows -- it's in the boot sector, so it's already
164 ; loaded and ready for us
166 bsOemName db 'EXTLINUX' ; The SYS command sets this, so...
168 ; These are the fields we actually care about. We end up expanding them
169 ; all to dword size early in the code, so generate labels for both
170 ; the expanded and unexpanded versions.
173 bx %+ %1 equ SuperInfo+($-superblock)*8+4
178 bx %+ %1 equ SuperInfo+($-superblock)*8
183 bx %+ %1 equ $ ; no expansion for dwords
198 superinfo_size equ ($-superblock)-1 ; How much to expand
202 ; This is as far as FAT12/16 and FAT32 are consistent
204 zb 54 ; FAT12/16 need 26 more bytes,
205 ; FAT32 need 54 more bytes
206 superblock_len equ $-superblock
209 ; Note we don't check the constraints above now; we did that at install
213 cli ; No interrupts yet, please
220 mov sp,StackBuf ; Just below BSS
223 ; DS:SI may contain a partition table entry. Preserve it for us.
225 mov cx,8 ; Save partition info
229 mov ds,ax ; Now we can initialize DS...
232 ; Now sautee the BIOS floppy info block to that it will support decent-
233 ; size transfers; the floppy block is 11 bytes and is stored in the
234 ; INT 1Eh vector (brilliant waste of resources, eh?)
236 ; Of course, if BIOSes had been properly programmed, we wouldn't have
237 ; had to waste precious space with this code.
240 lfs si,[bx] ; FS:SI -> original fdctab
241 push fs ; Save on stack in case we need to bail
244 ; Save the old fdctab even if hard disk so the stack layout
245 ; is the same. The instructions above do not change the flags
246 mov [DriveNumber],dl ; Save drive number in DL
247 and dl,dl ; If floppy disk (00-7F), assume no
252 mov cl,6 ; 12 bytes (CX == 0)
253 ; es:di -> FloppyTable already
254 ; This should be safe to do now, interrupts are off...
255 mov [bx],di ; FloppyTable
256 mov [bx+2],ax ; Segment 0
257 fs rep movsw ; Faster to move words
258 mov cl,[bsSecPerTrack] ; Patch the sector count
261 int 13h ; Some BIOSes need this
263 jmp short not_harddisk
265 ; The drive number and possibly partition information was passed to us
266 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
267 ; trust that rather than what the superblock contains.
269 ; Would it be better to zero out bsHidden if we don't have a partition table?
271 ; Note: di points to beyond the end of PartInfo
274 test byte [di-16],7Fh ; Sanity check: "active flag" should
275 jnz no_partition ; be 00 or 80
276 mov eax,[di-8] ; Partition offset (dword)
280 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
281 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
282 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
283 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
285 ; DL == drive # still
292 inc dx ; Contains # of heads - 1
295 mov [bsSecPerTrack],cx
299 ; Ready to enable interrupts, captain
305 ; Do we have EBIOS (EDD)?
309 mov ah,41h ; EDD existence query
315 test cl,1 ; Extended disk access functionality set
318 ; We have EDD support...
320 mov byte [getlinsec+1],getlinsec_ebios-(getlinsec+2)
324 ; Load the first sector of LDLINUX.SYS; this used to be all proper
325 ; with parsing the superblock and root directory; it doesn't fit
326 ; together with EBIOS support, unfortunately.
328 mov eax,[FirstSector] ; Sector start
329 mov bx,ldlinux_sys ; Where to load it
332 ; Some modicum of integrity checking
333 cmp dword [ldlinux_magic],LDLINUX_MAGIC
335 cmp dword [ldlinux_magic+4],HEXDATE
342 ; kaboom: write a message and bail out.
347 mov sp,StackBuf-4 ; Reset stack
348 mov ds,si ; Reset data segment
349 pop dword [fdctab] ; Restore FDC table
350 .patch: mov si,bailmsg
351 call writestr ; Returns with AL = 0
353 int 16h ; Wait for keypress
354 int 19h ; And try once more to boot...
355 .norge: jmp short .norge ; If int 19h returned; this is the end
359 ; writestr: write a null-terminated string to the console
360 ; This assumes we're on page 0. This is only used for early
361 ; messages, so it should be OK.
367 mov ah,0Eh ; Write to screen as TTY
368 mov bx,0007h ; Attribute
374 ; xint13: wrapper for int 13h which will retry 6 times and then die,
375 ; AND save all registers except BP
387 jmp strict near kaboom ; Patched
391 ; getonesec: get one disk sector
394 mov bp,1 ; One sector
398 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
399 ; number in EAX into the buffer at ES:BX. We try to optimize
400 ; by loading up to a whole track at a time, but the user
401 ; is responsible for not crossing a 64K boundary.
402 ; (Yes, BP is weird for a count, but it was available...)
404 ; On return, BX points to the first byte after the transferred
407 ; This routine assumes CS == DS, and trashes most registers.
409 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
410 ; that is dead from that point; this saves space. However, please keep
411 ; the order to dst,src to keep things sane.
414 jmp strict short getlinsec_cbios ; This is patched
419 ; getlinsec implementation for EBIOS (EDD)
422 mov si,dapa ; Load up the DAPA
427 push bp ; Sectors left
428 call maxtrans ; Enforce maximum transfer size
432 mov ah,42h ; Extended Read
435 movzx eax,word [si+2] ; Sectors we read
436 add [si+8],eax ; Advance sector pointer
437 sub bp,ax ; Sectors left
438 shl ax,9 ; 512-byte sectors
439 add [si+4],ax ; Advance buffer pointer
442 mov eax,[si+8] ; Next sector
443 mov bx,[si+4] ; Buffer pointer
449 ; getlinsec implementation for legacy CBIOS
457 movzx esi,word [bsSecPerTrack]
458 movzx edi,word [bsHeads]
460 ; Dividing by sectors to get (track,sector): we may have
461 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
463 xor edx,edx ; Zero-extend LBA to 64 bits
466 xchg cx,dx ; CX <- sector index (0-based)
469 div edi ; Convert track to head/cyl
471 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
472 ; BP = sectors to transfer, SI = bsSecPerTrack,
473 ; ES:BX = data target
476 call maxtrans ; Enforce maximum transfer size
478 ; Must not cross track boundaries, so BP <= SI-CX
485 shl ah,6 ; Because IBM was STOOPID
486 ; and thought 8 bits were enough
487 ; then thought 10 bits were enough...
488 inc cx ; Sector numbers are 1-based, sigh
493 xchg ax,bp ; Sector to transfer count
494 mov ah,02h ; Read sectors
497 shl ax,9 ; Convert sectors in AL to bytes in AX
508 ; Truncate BP to MaxTransfer
517 ; Error message on failure
519 bailmsg: db 'Boot failed', 0Dh, 0Ah, 0
522 ; EBIOS disk address packet
527 .count: dw 0 ; Block count
528 .off: dw 0 ; Offset of buffer
529 .seg: dw 0 ; Segment of buffer
530 .lba: dd 0 ; LBA (LSW)
535 bs_checkpt_off equ ($-$$)
537 %if bs_checkpt_off > 1F8h
538 %error "Boot sector overflow"
544 FirstSector dd 0xDEADBEEF ; Location of sector 1
545 MaxTransfer dw 0x007F ; Max transfer size
546 bootsignature dw 0AA55h
549 ; ===========================================================================
551 ; ===========================================================================
552 ; Start of LDLINUX.SYS
553 ; ===========================================================================
557 syslinux_banner db 0Dh, 0Ah
559 db version_str, ' ', date, ' ', 0
560 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
563 ldlinux_magic dd LDLINUX_MAGIC
567 ; This area is patched by the installer. It is found by looking for
568 ; LDLINUX_MAGIC, plus 8 bytes.
571 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
572 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
573 CheckSum dd 0 ; Checksum starting at ldlinux_sys
574 ; value = LDLINUX_MAGIC - [sum of dwords]
575 CurrentDir dd 2 ; "Current" directory inode number
577 ; Space for up to 64 sectors, the theoretical maximum
578 SectorPtrs times 64 dd 0
582 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
583 ; instead of 0000:7C00 and the like. We don't want to add anything
584 ; more to the boot sector, so it is written to not assume a fixed
585 ; value in CS, but we don't want to deal with that anymore from now
592 ; Tell the user we got this far
594 mov si,syslinux_banner
598 ; Patch disk error handling
600 mov word [xint13.disk_error+1],do_disk_error-(xint13.disk_error+3)
603 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
604 ; sector again, though.
608 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
614 lodsd ; First sector of this chunk
622 inc edx ; Next linear sector
623 cmp [esi],edx ; Does it match
624 jnz .chunk_ready ; If not, this is it
625 add esi,4 ; If so, add sector to chunk
626 jmp short .make_chunk
637 ; All loaded up, verify that we got what we needed.
638 ; Note: the checksum field is embedded in the checksum region, so
639 ; by the time we get to the end it should all cancel out.
644 mov edx,-LDLINUX_MAGIC
650 and edx,edx ; Should be zero
651 jz all_read ; We're cool, go for it!
654 ; Uh-oh, something went bad...
656 mov si,checksumerr_msg
661 ; -----------------------------------------------------------------------------
662 ; Subroutines that have to be in the first sector
663 ; -----------------------------------------------------------------------------
666 ; getlinsecsr: save registers, call getlinsec, restore registers
674 ; This routine captures disk errors, and tries to decide if it is
675 ; time to reduce the transfer size.
680 shr al,1 ; Try reducing the transfer size
682 jz kaboom ; If we can't, we're dead...
683 jmp xint13 ; Try again
694 ; Checksum error message
696 checksumerr_msg db 'Load error - ', 0 ; Boot failed appended
703 cmp word [Debug_Magic],0D00Dh
708 rl_checkpt equ $ ; Must be <= 8000h
710 rl_checkpt_off equ ($-$$)
712 %if rl_checkpt_off > 400h
713 %error "Sector 1 overflow"
717 ; ----------------------------------------------------------------------------
718 ; End of code and data that have to be in the first sector
719 ; ----------------------------------------------------------------------------
723 ; Let the user (and programmer!) know we got this far. This used to be
724 ; in Sector 1, but makes a lot more sense here.
730 ; Insane hack to expand the DOS superblock to dwords
736 mov cx,superinfo_size
740 stosd ; Store expanded word
742 stosd ; Store expanded byte
746 ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
749 mov eax,1024 >> SECTOR_SHIFT
754 ; Compute some values...
759 ; s_log_block_size = log2(blocksize) - 10
760 mov cl,[SuperBlock+s_log_block_size]
762 mov [ClustByteShift],cl
767 sub cl,2 ; 4 bytes/pointer
769 mov [PtrsPerBlock1],edx
771 mov [PtrsPerBlock2],edx
773 mov [PtrsPerBlock3],eax
775 sub cl,SECTOR_SHIFT-2
778 mov [SecPerClust],eax
783 ; Common initialization code
786 %include "cpuinit.inc"
789 ; Initialize the metadata cache
794 ; Now, everything is "up and running"... patch kaboom for more
795 ; verbosity and using the full screen system
798 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
801 ; Now we're all set to start with our *real* business. First load the
802 ; configuration file (if any) and parse it.
804 ; In previous versions I avoided using 32-bit registers because of a
805 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
806 ; random. I figure, though, that if there are any of those still left
807 ; they probably won't be trying to install Linux on them...
809 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
810 ; to take'm out. In fact, we may want to put them back if we're going
811 ; to boot ELKS at some point.
815 ; Load configuration file
823 ; Now we have the config file open. Parse the config file and
824 ; run the user interface.
829 ; Linux kernel loading code is common.
831 %include "runkernel.inc"
834 ; COMBOOT-loading code
836 %include "comboot.inc"
838 %include "cmdline.inc"
841 ; Boot sector loading code
843 %include "bootsect.inc"
846 ; abort_check: let the user abort with <ESC> or <Ctrl-C>
857 ac_kill: mov si,aborted_msg
860 ; abort_load: Called by various routines which wants to print a fatal
861 ; error message and return to the command prompt. Since this
862 ; may happen at just about any stage of the boot process, assume
863 ; our state is messed up, and just reset the segment registers
864 ; and the stack forcibly.
866 ; SI = offset (in _text) of error message to print
869 mov ax,cs ; Restore CS = DS = ES
873 mov sp,StackBuf-2*3 ; Reset stack
874 mov ss,ax ; Just in case...
876 call cwritestr ; Expects SI -> error msg
877 al_ok: jmp enter_command ; Return to command prompt
885 ; allocate_file: Allocate a file structure
898 .check: cmp dword [bx], byte 0
900 add bx,open_file_t_size ; ZF = 0
902 ; ZF = 0 if we fell out of the loop
907 ; Open a file indicated by an inode number in EAX
909 ; NOTE: This file considers finding a zero-length file an
910 ; error. This is so we don't have to deal with that special
911 ; case elsewhere in the program (most loops have the test
917 ; DX:AX = EAX = file length in bytes
921 open_inode.allocate_failure:
927 jnz .allocate_failure
930 ; First, get the appropriate inode group and index
931 dec eax ; There is no inode 0
933 mov [bx+file_sector],edx
934 div dword [SuperBlock+s_inodes_per_group]
935 ; EAX = inode group; EDX = inode within group
938 ; Now, we need the block group descriptor.
939 ; To get that, we first need the relevant descriptor block.
941 shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
943 div dword [ClustSize]
944 ; eax = block #, edx = offset in block
945 add eax,dword [SuperBlock+s_first_data_block]
946 inc eax ; s_first_data_block+1
949 call getcachesector ; Get the group descriptor
951 mov esi,[gs:si+bg_inode_table] ; Get inode table block #
952 pop eax ; Get inode within group
953 movzx edx, word [SuperBlock+s_inode_size]
955 ; edx:eax = byte offset in inode table
956 div dword [ClustSize]
957 ; eax = block # versus inode table, edx = offset in block
959 shl eax,cl ; Turn into sector
963 mov [bx+file_in_sec],eax
966 mov [bx+file_in_off],dx
970 mov eax,[gs:si+i_size]
972 add eax,SECTOR_SIZE-1
974 mov [bx+file_left],eax
978 shr edx,16 ; 16-bitism, sigh
979 and eax,eax ; ZF clear unless zero-length file
985 ; Deallocates a file structure (pointer in SI)
989 mov dword [si],0 ; First dword == file_left
994 ; Search the root directory for a pre-mangled filename in DS:DI.
996 ; NOTE: This file considers finding a zero-length file an
997 ; error. This is so we don't have to deal with that special
998 ; case elsewhere in the program (most loops have the test
1004 ; DX:AX = EAX = file length in bytes
1008 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
1011 mov eax,[CurrentDir]
1013 cmp byte [di],'/' ; Absolute filename?
1015 mov eax,EXT2_ROOT_INO
1019 ; At this point, EAX contains the directory inode,
1020 ; and DS:DI contains a pathname tail.
1026 mov cx,[SecPerClust]
1029 pushf ; Save EOF flag
1031 cmp dword [bx+d_inode],0
1036 mov cx,[bx+d_name_len]
1044 add bx,[bx+d_rec_len]
1049 jnc .readdir ; There is more
1054 mov eax,[si+d_inode]
1057 je .finish ; It's a real file; done
1059 jne .nope ; False alarm
1061 ; It's a match, but it's a directory.
1064 pop si ; Adjust stack (di)
1065 pop si ; Adjust stack (flags)
1070 .finish: ; We found it; now we need to open the file
1071 call close ; Close directory
1072 pop si ; Adjust stack (di)
1073 pop si ; Adjust stack (flags)
1078 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1079 ; to by ES:DI; ends on encountering any whitespace.
1081 ; This verifies that a filename is < FILENAME_MAX characters,
1082 ; doesn't contain whitespace, zero-pads the output buffer,
1083 ; and removes redundant slashes,
1084 ; so "repe cmpsb" can do a compare, and the
1085 ; path-searching routine gets a bit of an easier job.
1087 ; FIX: we may want to support \-escapes here (and this would
1093 mov cx,FILENAME_MAX-1
1098 cmp al,' ' ; If control or space, end
1100 cmp al,ah ; Repeated slash?
1107 .mn_skip: loop .mn_loop
1109 cmp bx,di ; At the beginning of the buffer?
1111 cmp byte [di-1],'/' ; Terminal slash?
1113 .mn_kill: dec di ; If so, remove it
1117 inc cx ; At least one null byte
1118 xor ax,ax ; Zero-fill name
1124 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1125 ; filename to the conventional representation. This is needed
1126 ; for the BOOT_IMAGE= parameter for the kernel.
1127 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1128 ; known to be shorter.
1130 ; DS:SI -> input mangled file name
1131 ; ES:DI -> output buffer
1133 ; On return, DI points to the first byte after the output name,
1134 ; which is set to a null byte.
1136 unmangle_name: call strcpy
1137 dec di ; Point to final null byte
1141 ; writechr: Write a single character in AL to the console without
1142 ; mangling any registers; handle video pages correctly.
1145 call write_serial ; write to serial port if needed
1149 mov bl,07h ; attribute
1150 mov bh,[cs:BIOS_page] ; current page
1158 ; kaboom2: once everything is loaded, replace the part of kaboom
1159 ; starting with "kaboom.patch" with this part
1162 mov si,err_bootfailed
1166 int 19h ; And try once more to boot...
1167 .norge: jmp short .norge ; If int 19h returned; this is the end
1171 ; linsector: Convert a linear sector index in a file to a linear sector number
1172 ; EAX -> linear sector number
1173 ; DS:SI -> open_file_t
1175 ; Returns next sector number in EAX; CF on EOF (not an error!)
1188 shr eax,cl ; Convert to block number
1190 mov eax,[si+file_in_sec]
1192 call getcachesector ; Get inode
1193 add si,[bx+file_in_off] ; Get *our* inode
1195 lea ebx,[i_block+4*eax]
1196 cmp eax,EXT2_NDIR_BLOCKS
1198 mov ebx,[gs:si+i_block+4*EXT2_IND_BLOCK]
1199 sub eax,EXT2_NDIR_BLOCKS
1200 mov ebp,[PtrsPerBlock1]
1202 mov ebx,[gs:si+i_block+4*EXT2_DIND_BLOCK]
1204 mov ebp,[PtrsPerBlock2]
1207 mov ebx,[gs:si+i_block+4*EXT2_TIND_BLOCK]
1211 ; Triple indirect; eax contains the block no
1212 ; with respect to the start of the tind area;
1213 ; ebx contains the pointer to the tind block.
1215 div dword [PtrsPerBlock3]
1216 ; EAX = which dind block, EDX = block no in dind block
1218 shl ebx,cl ; Sector # for tind block
1220 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1224 shl bx,2 ; Convert to byte offset
1225 and bx,SECTOR_SIZE-1
1227 mov ebx,[gs:bx+si] ; Get the pointer
1228 mov eax,edx ; The int2 code wants the remainder...
1230 ; Double indirect; eax contains the block no
1231 ; with respect to the start of the dind area;
1232 ; ebx contains the pointer to the dind block.
1234 div dword [PtrsPerBlock2]
1235 ; EAX = which dind block, EDX = block no in dind block
1237 shl ebx,cl ; Sector # for tind block
1239 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1243 shl bx,2 ; Convert to byte offset
1244 and bx,SECTOR_SIZE-1
1246 mov ebx,[gs:bx+si] ; Get the pointer
1247 mov eax,edx ; The ind1 code wants the remainder...
1249 ; Single indirect; eax contains the block no
1250 ; with respect to the start of the ind area;
1251 ; ebx contains the pointer to the ind block.
1253 div dword [PtrsPerBlock1]
1254 ; EAX = which dind block, EDX = block no in dind block
1256 shl ebx,cl ; Sector # for tind block
1258 shr eax,SECTOR_SHIFT-2 ; Sector within tind block
1262 shl bx,2 ; Convert to byte offset
1263 and bx,SECTOR_SIZE-1
1266 mov ebx,[gs:bx+si] ; Get the pointer
1268 pop eax ; Get the sector index again
1269 shl ebx,cl ; Convert block number to sector
1270 and eax,[ClustMask] ; Add offset within block
1283 ; getfssec: Get multiple sectors from a file
1285 ; Same as above, except SI is a pointer to a open_file_t
1288 ; DS:SI -> Pointer to open_file_t
1289 ; CX -> Sector count (0FFFFh = until end of file)
1290 ; Must not exceed the ES segment
1291 ; Returns CF=1 on EOF (not necessarily error)
1292 ; All arguments are advanced to reflect data read.
1300 mov eax,[si] ; Current start index
1303 push eax ; Fragment start sector
1305 xor ebp,ebp ; Fragment sector count
1313 add ax,bx ; Now DI = how far into 64K block we are
1314 not ax ; Bytes left in 64K block
1316 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1318 jnb .do_read ; Unless there is at least 1 more sector room...
1319 inc ebx ; Sector index
1320 inc edx ; Linearly next sector
1327 pop eax ; Linear start sector
1329 lea eax,[eax+ebp-1] ; This is the last sector actually read
1331 add bx,bp ; Adjust buffer pointer
1350 ; -----------------------------------------------------------------------------
1352 ; -----------------------------------------------------------------------------
1354 %include "getc.inc" ; getc et al
1355 %include "conio.inc" ; Console I/O
1356 %include "writestr.inc" ; String output
1357 %include "parseconfig.inc" ; High-level config file handling
1358 %include "parsecmd.inc" ; Low-level config file handling
1359 %include "bcopy32.inc" ; 32-bit bcopy
1360 %include "loadhigh.inc" ; Load a file into high memory
1361 %include "font.inc" ; VGA font stuff
1362 %include "graphics.inc" ; VGA graphics
1363 %include "highmem.inc" ; High memory sizing
1364 %include "strcpy.inc" ; strcpy()
1365 %include "cache.inc"
1367 ; -----------------------------------------------------------------------------
1368 ; Begin data section
1369 ; -----------------------------------------------------------------------------
1372 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1374 boot_prompt db 'boot: ', 0
1375 wipe_char db BS, ' ', BS, 0
1376 err_notfound db 'Could not find kernel image: ',0
1377 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1378 err_noram db 'It appears your computer has less than '
1380 db 'K of low ("DOS")'
1382 db 'RAM. Linux needs at least this amount to boot. If you get'
1384 db 'this message in error, hold down the Ctrl key while'
1386 db 'booting, and I will take your word for it.', CR, LF, 0
1387 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1388 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1389 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1390 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1391 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1392 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1394 err_notdos db ': attempted DOS system call', CR, LF, 0
1395 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1396 err_bssimage db 'BSS images not supported.', CR, LF, 0
1397 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1398 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1399 db 'a key to continue.', CR, LF, 0
1400 ready_msg db 'Ready.', CR, LF, 0
1401 crlfloading_msg db CR, LF
1402 loading_msg db 'Loading ', 0
1405 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1408 crff_msg db CR, FF, 0
1409 ConfigName db 'extlinux.cfg',0 ; Unmangled form
1412 ; Command line options we'd like to take a look at
1414 ; mem= and vga= are handled as normal 32-bit integer values
1415 initrd_cmd db 'initrd='
1416 initrd_cmd_len equ 7
1419 ; Config file keyword table
1421 %include "keywords.inc"
1424 ; Extensions to search for (in *forward* order).
1427 exten_table: db '.cbt' ; COMBOOT (specific)
1428 db '.img' ; Disk image
1429 db '.bs', 0 ; Boot sector
1430 db '.com' ; COMBOOT (same as DOS)
1433 dd 0, 0 ; Need 8 null bytes here
1436 ; Misc initialized (data) variables
1438 %ifdef debug ; This code for debugging only
1439 debug_magic dw 0D00Dh ; Debug code sentinel
1443 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1444 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1445 BufSafeBytes dw trackbufsize ; = how many bytes?
1446 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1448 %if ( trackbufsize % SECTOR_SIZE ) != 0
1449 %error trackbufsize must be a multiple of SECTOR_SIZE
1452 align 4, db 0 ; Pad out any unfinished dword