1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
6 ; A program to boot Linux kernels off an ext2/ext3 filesystem.
8 ; Copyright (C) 1994-2007 H. Peter Anvin
10 ; This program is free software; you can redistribute it and/or modify
11 ; it under the terms of the GNU General Public License as published by
12 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
13 ; Boston MA 02111-1307, USA; either version 2 of the License, or
14 ; (at your option) any later version; incorporated herein by reference.
16 ; ****************************************************************************
20 %include "ext2_fs.inc"
23 ; Some semi-configurable constants... change on your own risk.
26 ; NASM 0.98.38 croaks if these are equ's rather than macros...
27 FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
28 FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size
29 NULLFILE equ 0 ; Null character == empty filename
30 NULLOFFSET equ 0 ; Position in which to look
31 retry_count equ 16 ; How patient are we with the disk?
32 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
33 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
35 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
36 MAX_OPEN equ (1 << MAX_OPEN_LG2)
39 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
41 MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
42 SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
43 ; (should be >= FILENAME_MAX)
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
65 vk_type: resb 1 ; Type of file
67 vk_append: resb max_cmd_len+1 ; Command line
69 vk_end: equ $ ; Should be <= vk_size
73 ; Segment assignments in the bottom 640K
74 ; Stick to the low 512K in case we're using something like M-systems flash
75 ; which load a driver into low RAM (evil!!)
77 ; 0000h - main code/data segment (and BIOS segment)
79 real_mode_seg equ 4000h
80 cache_seg equ 3000h ; 64K area for metadata cache
81 vk_seg equ 2000h ; Virtual kernels
82 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
83 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
86 ; File structure. This holds the information for each currently open file.
89 file_left resd 1 ; Number of sectors left (0 = free)
90 file_sector resd 1 ; Next linear sector to read
91 file_in_sec resd 1 ; Sector where inode lives
97 %if (open_file_t_size & (open_file_t_size-1))
98 %error "open_file_t is not a power of 2"
102 ; ---------------------------------------------------------------------------
104 ; ---------------------------------------------------------------------------
107 ; Memory below this point is reserved for the BIOS and the MBR
110 trackbufsize equ 8192
111 trackbuf resb trackbufsize ; Track buffer goes here
112 getcbuf resb trackbufsize
116 SuperBlock resb 1024 ; ext2 superblock
117 SuperInfo resq 16 ; DOS superblock expanded
118 ClustSize resd 1 ; Bytes/cluster ("block")
119 SecPerClust resd 1 ; Sectors/cluster
120 ClustMask resd 1 ; Sectors/cluster - 1
121 PtrsPerBlock1 resd 1 ; Pointers/cluster
122 PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2
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
144 ; Some of the things that have to be saved very early are saved
145 ; "close" to the initial stack pointer offset, in order to
146 ; reduce the code size...
148 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
149 PartInfo equ StackBuf ; Saved partition table entry
150 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
151 OrigFDCTabPtr equ StackBuf-8 ; The 2nd high dword on the stack
152 OrigESDI 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
221 push es ; Save initial ES:DI -> $PnP pointer
225 ; DS:SI may contain a partition table entry. Preserve it for us.
227 mov cx,8 ; Save partition info
231 mov ds,ax ; Now we can initialize DS...
234 ; Now sautee the BIOS floppy info block to that it will support decent-
235 ; size transfers; the floppy block is 11 bytes and is stored in the
236 ; INT 1Eh vector (brilliant waste of resources, eh?)
238 ; Of course, if BIOSes had been properly programmed, we wouldn't have
239 ; had to waste precious space with this code.
242 lfs si,[bx] ; FS:SI -> original fdctab
243 push fs ; Save on stack in case we need to bail
246 ; Save the old fdctab even if hard disk so the stack layout
247 ; is the same. The instructions above do not change the flags
248 mov [DriveNumber],dl ; Save drive number in DL
249 and dl,dl ; If floppy disk (00-7F), assume no
254 mov cl,6 ; 12 bytes (CX == 0)
255 ; es:di -> FloppyTable already
256 ; This should be safe to do now, interrupts are off...
257 mov [bx],di ; FloppyTable
258 mov [bx+2],ax ; Segment 0
259 fs rep movsw ; Faster to move words
260 mov cl,[bsSecPerTrack] ; Patch the sector count
263 int 13h ; Some BIOSes need this
265 jmp short not_harddisk
267 ; The drive number and possibly partition information was passed to us
268 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
269 ; trust that rather than what the superblock contains.
271 ; Would it be better to zero out bsHidden if we don't have a partition table?
273 ; Note: di points to beyond the end of PartInfo
276 test byte [di-16],7Fh ; Sanity check: "active flag" should
277 jnz no_partition ; be 00 or 80
278 mov eax,[di-8] ; Partition offset (dword)
282 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
283 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
284 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
285 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
287 ; DL == drive # still
294 inc dx ; Contains # of heads - 1
297 mov [bsSecPerTrack],cx
301 ; Ready to enable interrupts, captain
306 ; Do we have EBIOS (EDD)?
310 mov ah,41h ; EDD existence query
316 test cl,1 ; Extended disk access functionality set
319 ; We have EDD support...
321 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
325 ; Load the first sector of LDLINUX.SYS; this used to be all proper
326 ; with parsing the superblock and root directory; it doesn't fit
327 ; together with EBIOS support, unfortunately.
329 mov eax,[FirstSector] ; Sector start
330 mov bx,ldlinux_sys ; Where to load it
333 ; Some modicum of integrity checking
334 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
341 ; getonesec: get one disk sector
344 mov bp,1 ; One sector
348 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
349 ; number in EAX into the buffer at ES:BX. We try to optimize
350 ; by loading up to a whole track at a time, but the user
351 ; is responsible for not crossing a 64K boundary.
352 ; (Yes, BP is weird for a count, but it was available...)
354 ; On return, BX points to the first byte after the transferred
357 ; This routine assumes CS == DS, and trashes most registers.
359 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
360 ; that is dead from that point; this saves space. However, please keep
361 ; the order to dst,src to keep things sane.
364 add eax,[bsHidden] ; Add partition offset
365 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
367 .jmp: jmp strict short getlinsec_cbios
372 ; getlinsec implementation for EBIOS (EDD)
376 push bp ; Sectors left
378 call maxtrans ; Enforce maximum transfer size
379 movzx edi,bp ; Sectors we are about to read
396 mov ah,42h ; Extended Read
400 lea sp,[si+16] ; Remove DAPA
403 add eax,edi ; Advance sector pointer
404 sub bp,di ; Sectors left
405 shl di,SECTOR_SHIFT ; 512-byte sectors
406 add bx,di ; Advance buffer pointer
413 ; Some systems seem to get "stuck" in an error state when
414 ; using EBIOS. Doesn't happen when using CBIOS, which is
415 ; good, since some other systems get timeout failures
416 ; waiting for the floppy disk to spin up.
418 pushad ; Try resetting the device
423 loop .retry ; CX-- and jump if not zero
425 ;shr word [MaxTransfer],1 ; Reduce the transfer size
428 ; Total failure. Try falling back to CBIOS.
429 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
430 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
433 ; ... fall through ...
438 ; getlinsec implementation for legacy CBIOS
447 movzx esi,word [bsSecPerTrack]
448 movzx edi,word [bsHeads]
450 ; Dividing by sectors to get (track,sector): we may have
451 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
455 xchg cx,dx ; CX <- sector index (0-based)
458 div edi ; Convert track to head/cyl
460 ; We should test this, but it doesn't fit...
465 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
466 ; BP = sectors to transfer, SI = bsSecPerTrack,
467 ; ES:BX = data target
470 call maxtrans ; Enforce maximum transfer size
472 ; Must not cross track boundaries, so BP <= SI-CX
479 shl ah,6 ; Because IBM was STOOPID
480 ; and thought 8 bits were enough
481 ; then thought 10 bits were enough...
482 inc cx ; Sector numbers are 1-based, sigh
487 xchg ax,bp ; Sector to transfer count
488 mov ah,02h ; Read sectors
496 movzx ecx,al ; ECX <- sectors transferred
497 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
512 xchg ax,bp ; Sectors transferred <- 0
513 shr word [MaxTransfer],1
515 ; Fall through to disk_error
518 ; kaboom: write a message and bail out.
524 mov sp,StackBuf-4 ; Reset stack
525 mov ds,si ; Reset data segment
526 pop dword [fdctab] ; Restore FDC table
527 .patch: ; When we have full code, intercept here
530 ; Write error message, this assumes screen page 0
534 mov ah,0Eh ; Write to screen as TTY
535 mov bx,0007h ; Attribute
540 .again: int 16h ; Wait for keypress
541 ; NB: replaced by int 18h if
542 ; chosen at install time..
543 int 19h ; And try once more to boot...
544 .norge: jmp short .norge ; If int 19h returned; this is the end
547 ; Truncate BP to MaxTransfer
556 ; Error message on failure
558 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
560 ; This fails if the boot sector overflows
563 FirstSector dd 0xDEADBEEF ; Location of sector 1
564 MaxTransfer dw 0x007F ; Max transfer size
566 ; This field will be filled in 0xAA55 by the installer, but we abuse it
567 ; to house a pointer to the INT 16h instruction at
568 ; kaboom.again, which gets patched to INT 18h in RAID mode.
569 bootsignature dw kaboom.again-bootsec
572 ; ===========================================================================
574 ; ===========================================================================
575 ; Start of LDLINUX.SYS
576 ; ===========================================================================
580 syslinux_banner db 0Dh, 0Ah
582 db version_str, ' ', date, ' ', 0
583 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
586 ldlinux_magic dd LDLINUX_MAGIC
587 dd LDLINUX_MAGIC^HEXDATE
590 ; This area is patched by the installer. It is found by looking for
591 ; LDLINUX_MAGIC, plus 8 bytes.
594 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys,
596 LDLSectors dw 0 ; Number of sectors, not including
597 ; bootsec & this sec, but including the two ADVs
598 CheckSum dd 0 ; Checksum starting at ldlinux_sys
599 ; value = LDLINUX_MAGIC - [sum of dwords]
600 CurrentDir dd 2 ; "Current" directory inode number
602 ; Space for up to 64 sectors, the theoretical maximum
603 SectorPtrs times 64 dd 0
607 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
608 ; instead of 0000:7C00 and the like. We don't want to add anything
609 ; more to the boot sector, so it is written to not assume a fixed
610 ; value in CS, but we don't want to deal with that anymore from now
617 ; Tell the user we got this far
619 mov si,syslinux_banner
623 ; Tell the user if we're using EBIOS or CBIOS
627 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
635 %define HAVE_BIOSNAME 1
640 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
641 ; sector again, though.
645 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
651 lodsd ; First sector of this chunk
659 inc edx ; Next linear sector
660 cmp [si],edx ; Does it match
661 jnz .chunk_ready ; If not, this is it
662 add si,4 ; If so, add sector to chunk
663 jmp short .make_chunk
674 ; All loaded up, verify that we got what we needed.
675 ; Note: the checksum field is embedded in the checksum region, so
676 ; by the time we get to the end it should all cancel out.
681 mov edx,-LDLINUX_MAGIC
687 and edx,edx ; Should be zero
688 jz all_read ; We're cool, go for it!
691 ; Uh-oh, something went bad...
693 mov si,checksumerr_msg
698 ; -----------------------------------------------------------------------------
699 ; Subroutines that have to be in the first sector
700 ; -----------------------------------------------------------------------------
704 ; writestr: write a null-terminated string to the console
705 ; This assumes we're on page 0. This is only used for early
706 ; messages, so it should be OK.
712 mov ah,0Eh ; Write to screen as TTY
713 mov bx,0007h ; Attribute
719 ; getlinsecsr: save registers, call getlinsec, restore registers
727 ; Checksum error message
729 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
734 cbios_name db 'CBIOS', 0
735 ebios_name db 'EBIOS', 0
742 cmp word [Debug_Magic],0D00Dh
747 rl_checkpt equ $ ; Must be <= 8000h
749 rl_checkpt_off equ ($-$$)
751 %if rl_checkpt_off > 400h
752 %error "Sector 1 overflow"
756 ; ----------------------------------------------------------------------------
757 ; End of code and data that have to be in the first sector
758 ; ----------------------------------------------------------------------------
762 ; Let the user (and programmer!) know we got this far. This used to be
763 ; in Sector 1, but makes a lot more sense here.
769 ; Insane hack to expand the DOS superblock to dwords
775 mov cx,superinfo_size
779 stosd ; Store expanded word
781 stosd ; Store expanded byte
785 ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
788 mov eax,1024 >> SECTOR_SHIFT
793 ; Compute some values...
798 ; s_log_block_size = log2(blocksize) - 10
799 mov cl,[SuperBlock+s_log_block_size]
801 mov [ClustByteShift],cl
809 mov [SecPerClust],eax
813 add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer
815 mov [PtrsPerBlock1],edx
817 mov [PtrsPerBlock2],edx
820 ; Common initialization code
823 %include "cpuinit.inc"
826 ; Initialize the metadata cache
831 ; Now, everything is "up and running"... patch kaboom for more
832 ; verbosity and using the full screen system
835 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
838 ; Now we're all set to start with our *real* business. First load the
839 ; configuration file (if any) and parse it.
841 ; In previous versions I avoided using 32-bit registers because of a
842 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
843 ; random. I figure, though, that if there are any of those still left
844 ; they probably won't be trying to install Linux on them...
846 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
847 ; to take'm out. In fact, we may want to put them back if we're going
848 ; to boot ELKS at some point.
852 ; Load configuration file
855 mov si,config_name ; Save config file name
864 ; Now we have the config file open. Parse the config file and
865 ; run the user interface.
870 ; getlinsec_ext: same as getlinsec, except load any sector from the zero
871 ; block as all zeros; use to load any data derived
872 ; from an ext2 block pointer, i.e. anything *except the
879 cmp eax,[SecPerClust]
880 jae getlinsec ; Nothing fancy
882 ; If we get here, at least part of what we want is in the
883 ; zero block. Zero one sector at a time and loop.
888 mov cx,SECTOR_SIZE >> 2
899 ; allocate_file: Allocate a file structure
912 .check: cmp dword [bx], byte 0
914 add bx,open_file_t_size ; ZF = 0
916 ; ZF = 0 if we fell out of the loop
921 ; Open a file indicated by an inode number in EAX
923 ; NOTE: This file considers finding a zero-length file an
924 ; error. This is so we don't have to deal with that special
925 ; case elsewhere in the program (most loops have the test
931 ; DX:AX = EAX = file length in bytes
932 ; ThisInode = the first 128 bytes of the inode
936 ; Assumes CS == DS == ES.
938 open_inode.allocate_failure:
948 jnz .allocate_failure
952 ; First, get the appropriate inode group and index
953 dec eax ; There is no inode 0
955 mov [bx+file_sector],edx
956 div dword [SuperBlock+s_inodes_per_group]
957 ; EAX = inode group; EDX = inode within group
960 ; Now, we need the block group descriptor.
961 ; To get that, we first need the relevant descriptor block.
963 shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
965 div dword [ClustSize]
966 ; eax = block #, edx = offset in block
967 add eax,dword [SuperBlock+s_first_data_block]
968 inc eax ; s_first_data_block+1
976 call getcachesector ; Get the group descriptor
978 mov esi,[gs:si+bg_inode_table] ; Get inode table block #
979 pop eax ; Get inode within group
980 movzx edx, word [SuperBlock+s_inode_size]
982 ; edx:eax = byte offset in inode table
983 div dword [ClustSize]
984 ; eax = block # versus inode table, edx = offset in block
986 shl eax,cl ; Turn into sector
990 mov [bx+file_in_sec],eax
993 mov [bx+file_in_off],dx
997 mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
1001 mov ax,[ThisInode+i_mode]
1002 mov [bx+file_mode],ax
1003 mov eax,[ThisInode+i_size]
1005 add eax,SECTOR_SIZE-1
1006 shr eax,SECTOR_SHIFT
1007 mov [bx+file_left],eax
1011 shr edx,16 ; 16-bitism, sigh
1012 and eax,eax ; ZF clear unless zero-length file
1021 ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
1026 ; Deallocates a file structure (pointer in SI)
1032 mov dword [si],0 ; First dword == file_left
1037 ; Search the root directory for a pre-mangled filename in DS:DI.
1039 ; NOTE: This file considers finding a zero-length file an
1040 ; error. This is so we don't have to deal with that special
1041 ; case elsewhere in the program (most loops have the test
1047 ; DX:AX = EAX = file length in bytes
1051 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
1057 mov byte [SymlinkCtr],MAX_SYMLINKS
1059 mov eax,[CurrentDir]
1062 cmp byte [di],'/' ; Absolute filename?
1064 mov eax,EXT2_ROOT_INO
1069 ; At this point, EAX contains the directory inode,
1070 ; and DS:DI contains a pathname tail.
1072 push eax ; Save directory inode
1075 jz .done ; If error, done
1077 mov cx,[si+file_mode]
1078 shr cx,S_IFSHIFT ; Get file type
1083 add sp,4 ; Drop directory inode
1090 ; Otherwise, something bad...
1099 and eax,eax ; Set/clear ZF
1109 cmp byte [di],0 ; End of path?
1110 je .done ; If so, done
1111 jmp .err ; Otherwise, error
1117 pop dword [ThisDir] ; Remember what directory we're searching
1119 cmp byte [di],0 ; More path?
1120 je .err ; If not, bad
1122 .skipslash: ; Skip redundant slashes
1131 mov cx,[SecPerClust]
1134 pushf ; Save EOF flag
1135 push si ; Save filesystem pointer
1137 cmp dword [bx+d_inode],0
1141 movzx cx,byte [bx+d_name_len]
1148 add bx,[bx+d_rec_len]
1154 jnc .readdir ; There is more
1155 jmp .err ; Otherwise badness...
1158 mov eax,[bx+d_inode]
1160 ; Does this match the end of the requested filename?
1166 ; We found something; now we need to open the file
1168 pop bx ; Adjust stack (di)
1170 call close_file ; Close directory
1171 pop bx ; Adjust stack (flags)
1175 ; It's a symlink. We have to determine if it's a fast symlink
1176 ; (data stored in the inode) or not (data stored as a regular
1177 ; file.) Either which way, we start from the directory
1178 ; which we just visited if relative, or from the root directory
1179 ; if absolute, and append any remaining part of the path.
1182 dec byte [SymlinkCtr]
1183 jz .err ; Too many symlink references
1185 cmp eax,SYMLINK_SECTORS*SECTOR_SIZE
1186 jae .err ; Symlink too long
1188 ; Computation for fast symlink, as defined by ext2/3 spec
1190 cmp [ThisInode+i_file_acl],ecx
1191 setne cl ; ECX <- i_file_acl ? 1 : 0
1192 cmp [ThisInode+i_blocks],ecx
1195 ; It's a fast symlink
1197 call close_file ; We've got all we need
1198 mov si,ThisInode+i_block
1201 mov di,SymlinkTmpBuf
1212 mov bp,SymlinkTmpBufEnd
1214 jc .err_noclose ; Buffer overflow
1216 ; Now copy it to the "real" buffer; we need to have
1217 ; two buffers so we avoid overwriting the tail on the
1219 mov si,SymlinkTmpBuf
1224 mov eax,[ThisDir] ; Resume searching previous directory
1228 mov bx,SymlinkTmpBuf
1229 mov cx,SYMLINK_SECTORS
1231 ; The EOF closed the file
1233 mov si,di ; SI = filename tail
1234 mov di,SymlinkTmpBuf
1235 add di,ax ; AX = file length
1241 SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64
1242 SymlinkTmpBuf equ trackbuf
1243 SymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64
1249 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1250 ; to by ES:DI; ends on encountering any whitespace.
1253 ; This verifies that a filename is < FILENAME_MAX characters,
1254 ; doesn't contain whitespace, zero-pads the output buffer,
1255 ; and removes redundant slashes,
1256 ; so "repe cmpsb" can do a compare, and the
1257 ; path-searching routine gets a bit of an easier job.
1259 ; FIX: we may want to support \-escapes here (and this would
1266 mov cx,FILENAME_MAX-1
1271 cmp al,' ' ; If control or space, end
1273 cmp al,ah ; Repeated slash?
1280 .mn_skip: loop .mn_loop
1282 cmp bx,di ; At the beginning of the buffer?
1284 cmp byte [di-1],'/' ; Terminal slash?
1286 .mn_kill: dec di ; If so, remove it
1290 inc cx ; At least one null byte
1291 xor ax,ax ; Zero-fill name
1298 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1299 ; filename to the conventional representation. This is needed
1300 ; for the BOOT_IMAGE= parameter for the kernel.
1301 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1302 ; known to be shorter.
1304 ; DS:SI -> input mangled file name
1305 ; ES:DI -> output buffer
1307 ; On return, DI points to the first byte after the output name,
1308 ; which is set to a null byte.
1310 unmangle_name: call strcpy
1311 dec di ; Point to final null byte
1316 ; kaboom2: once everything is loaded, replace the part of kaboom
1317 ; starting with "kaboom.patch" with this part
1320 mov si,err_bootfailed
1322 cmp byte [kaboom.again+1],18h ; INT 18h version?
1326 int 19h ; And try once more to boot...
1327 .norge: jmp short .norge ; If int 19h returned; this is the end
1331 .noreg: jmp short .noreg ; Nynorsk
1335 ; linsector: Convert a linear sector index in a file to a linear sector number
1336 ; EAX -> linear sector number
1337 ; DS:SI -> open_file_t
1339 ; Returns next sector number in EAX; CF on EOF (not an error!)
1350 push eax ; Save sector index
1352 shr eax,cl ; Convert to block number
1354 mov eax,[si+file_in_sec]
1356 call getcachesector ; Get inode
1357 add si,[bx+file_in_off] ; Get *our* inode
1359 lea ebx,[i_block+4*eax]
1360 cmp eax,EXT2_NDIR_BLOCKS
1362 mov ebx,i_block+4*EXT2_IND_BLOCK
1363 sub eax,EXT2_NDIR_BLOCKS
1364 mov ebp,[PtrsPerBlock1]
1367 mov ebx,i_block+4*EXT2_DIND_BLOCK
1369 mov ebp,[PtrsPerBlock2]
1372 mov ebx,i_block+4*EXT2_TIND_BLOCK
1376 ; Triple indirect; eax contains the block no
1377 ; with respect to the start of the tind area;
1378 ; ebx contains the pointer to the tind block.
1380 div dword [PtrsPerBlock2]
1381 ; EAX = which dind block, EDX = pointer within dind block
1383 shr eax,SECTOR_SHIFT-2
1389 and bx,(SECTOR_SIZE >> 2)-1
1391 mov eax,edx ; The ind2 code wants the remainder...
1394 ; Double indirect; eax contains the block no
1395 ; with respect to the start of the dind area;
1396 ; ebx contains the pointer to the dind block.
1398 div dword [PtrsPerBlock1]
1399 ; EAX = which ind block, EDX = pointer within ind block
1401 shr eax,SECTOR_SHIFT-2
1407 and bx,(SECTOR_SIZE >> 2)-1
1409 mov eax,edx ; The int1 code wants the remainder...
1412 ; Single indirect; eax contains the block no
1413 ; with respect to the start of the ind area;
1414 ; ebx contains the pointer to the ind block.
1416 shr eax,SECTOR_SHIFT-2
1422 and bx,(SECTOR_SIZE >> 2)-1
1426 mov ebx,[gs:bx+si] ; Get the pointer
1428 pop eax ; Get the sector index again
1429 shl ebx,cl ; Convert block number to sector
1430 and eax,[ClustMask] ; Add offset within block
1443 ; getfssec: Get multiple sectors from a file
1445 ; Same as above, except SI is a pointer to a open_file_t
1448 ; DS:SI -> Pointer to open_file_t
1449 ; CX -> Sector count (0FFFFh = until end of file)
1450 ; Must not exceed the ES segment
1451 ; Returns CF=1 on EOF (not necessarily error)
1452 ; All arguments are advanced to reflect data read.
1461 cmp ecx,[si] ; Number of sectors left
1466 mov eax,[si+file_sector] ; Current start index
1469 push eax ; Fragment start sector
1471 xor ebp,ebp ; Fragment sector count
1479 add ax,bx ; Now DI = how far into 64K block we are
1480 not ax ; Bytes left in 64K block
1482 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1484 jnb .do_read ; Unless there is at least 1 more sector room...
1485 inc edi ; Sector index
1486 inc edx ; Linearly next sector
1493 pop eax ; Linear start sector
1499 add bx,bp ; Adjust buffer pointer
1501 add [si+file_sector],ebp ; Next sector index
1502 sub [si],ebp ; Sectors consumed
1507 cmp dword [si],1 ; Did we run out of file?
1508 ; CF set if [SI] < 1, i.e. == 0
1515 ; -----------------------------------------------------------------------------
1517 ; -----------------------------------------------------------------------------
1519 %include "getc.inc" ; getc et al
1520 %include "conio.inc" ; Console I/O
1521 %include "plaincon.inc" ; writechr
1522 %include "writestr.inc" ; String output
1523 %include "configinit.inc" ; Initialize configuration
1524 %include "parseconfig.inc" ; High-level config file handling
1525 %include "parsecmd.inc" ; Low-level config file handling
1526 %include "bcopy32.inc" ; 32-bit bcopy
1527 %include "loadhigh.inc" ; Load a file into high memory
1528 %include "font.inc" ; VGA font stuff
1529 %include "graphics.inc" ; VGA graphics
1530 %include "highmem.inc" ; High memory sizing
1531 %include "strcpy.inc" ; strcpy()
1532 %include "strecpy.inc" ; strcpy with end pointer check
1533 %include "cache.inc" ; Metadata disk cache
1534 %include "adv.inc" ; Auxillary Data Vector
1536 ; -----------------------------------------------------------------------------
1537 ; Begin data section
1538 ; -----------------------------------------------------------------------------
1541 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1543 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1544 db 'a key to continue.', CR, LF, 0
1545 config_name db 'extlinux.conf',0 ; Unmangled form
1548 ; Command line options we'd like to take a look at
1550 ; mem= and vga= are handled as normal 32-bit integer values
1551 initrd_cmd db 'initrd='
1552 initrd_cmd_len equ 7
1555 ; Config file keyword table
1557 %include "keywords.inc"
1560 ; Extensions to search for (in *forward* order).
1563 exten_table: db '.cbt' ; COMBOOT (specific)
1564 db '.img' ; Disk image
1565 db '.bs', 0 ; Boot sector
1566 db '.com' ; COMBOOT (same as DOS)
1569 dd 0, 0 ; Need 8 null bytes here
1572 ; Misc initialized (data) variables
1574 %ifdef debug ; This code for debugging only
1575 debug_magic dw 0D00Dh ; Debug code sentinel
1579 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1580 BufSafeBytes dw trackbufsize ; = how many bytes?
1582 %if ( trackbufsize % SECTOR_SIZE ) != 0
1583 %error trackbufsize must be a multiple of SECTOR_SIZE