1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
6 ; A program to boot Linux kernels off an ext2/ext3 filesystem.
8 ; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
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 in high memory 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 3000h
80 cache_seg
equ 2000h ; 64K area for metadata cache
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_bytesleft resd
1 ; Number of bytes 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 trackbufsize
equ 8192
110 trackbuf resb trackbufsize
; Track buffer goes here
114 SuperBlock resb
1024 ; ext2 superblock
115 SuperInfo resq
16 ; DOS superblock expanded
116 ClustSize resd
1 ; Bytes/cluster ("block")
117 SecPerClust resd
1 ; Sectors/cluster
118 ClustMask resd
1 ; Sectors/cluster - 1
119 PtrsPerBlock1 resd
1 ; Pointers/cluster
120 PtrsPerBlock2 resd
1 ; (Pointers/cluster)^2
121 DriveNumber resb
1 ; BIOS drive number
122 ClustShift resb
1 ; Shift count for sectors/cluster
123 ClustByteShift resb
1 ; Shift count for bytes/cluster
125 alignb open_file_t_size
126 Files resb MAX_OPEN
*open_file_t_size
130 ; Some of the things that have to be saved very early are saved
131 ; "close" to the initial stack pointer offset, in order to
132 ; reduce the code size...
134 StackBuf
equ $
-44-32 ; Start the stack here (grow down - 4K)
135 PartInfo
equ StackBuf
; Saved partition table entry
136 FloppyTable
equ PartInfo
+16 ; Floppy info table (must follow PartInfo)
137 OrigFDCTabPtr
equ StackBuf
-8 ; The 2nd high dword on the stack
138 OrigESDI
equ StackBuf
-4 ; The high dword on the stack
141 ; Primary entry point. Tempting as though it may be, we can't put the
142 ; initial "cli" here; the jmp opcode in the first byte is part of the
143 ; "magic number" (using the term very loosely) for the DOS superblock.
146 jmp short start
; 2 bytes
149 ; "Superblock" follows -- it's in the boot sector, so it's already
150 ; loaded and ready for us
152 bsOemName
db 'EXTLINUX' ; The SYS command sets this, so...
154 ; These are the fields we actually care about. We end up expanding them
155 ; all to dword size early in the code, so generate labels for both
156 ; the expanded and unexpanded versions.
159 bx %+ %1 equ SuperInfo
+($
-superblock
)*8+4
164 bx %+ %1 equ SuperInfo
+($
-superblock
)*8
169 bx %+ %1 equ $
; no expansion for dwords
184 superinfo_size
equ ($
-superblock
)-1 ; How much to expand
188 ; This is as far as FAT12/16 and FAT32 are consistent
190 zb
54 ; FAT12/16 need 26 more bytes,
191 ; FAT32 need 54 more bytes
192 superblock_len
equ $
-superblock
195 ; Note we don't check the constraints above now; we did that at install
199 cli ; No interrupts yet, please
206 mov sp,StackBuf
; Just below BSS
207 push es ; Save initial ES:DI -> $PnP pointer
211 ; DS:SI may contain a partition table entry. Preserve it for us.
213 mov cx,8 ; Save partition info
217 mov ds,ax ; Now we can initialize DS...
220 ; Now sautee the BIOS floppy info block to that it will support decent-
221 ; size transfers; the floppy block is 11 bytes and is stored in the
222 ; INT 1Eh vector (brilliant waste of resources, eh?)
224 ; Of course, if BIOSes had been properly programmed, we wouldn't have
225 ; had to waste precious space with this code.
228 lfs si,[bx] ; FS:SI -> original fdctab
229 push fs ; Save on stack in case we need to bail
232 ; Save the old fdctab even if hard disk so the stack layout
233 ; is the same. The instructions above do not change the flags
234 mov [DriveNumber
],dl ; Save drive number in DL
235 and dl,dl ; If floppy disk (00-7F), assume no
240 mov cl,6 ; 12 bytes (CX == 0)
241 ; es:di -> FloppyTable already
242 ; This should be safe to do now, interrupts are off...
243 mov [bx],di ; FloppyTable
244 mov [bx+2],ax ; Segment 0
245 fs rep movsw ; Faster to move words
246 mov cl,[bsSecPerTrack
] ; Patch the sector count
249 int 13h ; Some BIOSes need this
251 jmp short not_harddisk
253 ; The drive number and possibly partition information was passed to us
254 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
255 ; trust that rather than what the superblock contains.
257 ; Would it be better to zero out bsHidden if we don't have a partition table?
259 ; Note: di points to beyond the end of PartInfo
262 test byte [di-16],7Fh
; Sanity check: "active flag" should
263 jnz no_partition
; be 00 or 80
264 mov eax,[di-8] ; Partition offset (dword)
268 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
269 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
270 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
271 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
273 ; DL == drive # still
280 inc dx ; Contains # of heads - 1
283 mov [bsSecPerTrack
],cx
287 ; Ready to enable interrupts, captain
292 ; Do we have EBIOS (EDD)?
296 mov ah,41h ; EDD existence query
302 test cl,1 ; Extended disk access functionality set
305 ; We have EDD support...
307 mov byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
311 ; Load the first sector of LDLINUX.SYS; this used to be all proper
312 ; with parsing the superblock and root directory; it doesn't fit
313 ; together with EBIOS support, unfortunately.
315 mov eax,[FirstSector
] ; Sector start
316 mov bx,ldlinux_sys
; Where to load it
319 ; Some modicum of integrity checking
320 cmp dword [ldlinux_magic
+4],LDLINUX_MAGIC^HEXDATE
327 ; getonesec: get one disk sector
330 mov bp,1 ; One sector
334 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
335 ; number in EAX into the buffer at ES:BX. We try to optimize
336 ; by loading up to a whole track at a time, but the user
337 ; is responsible for not crossing a 64K boundary.
338 ; (Yes, BP is weird for a count, but it was available...)
340 ; On return, BX points to the first byte after the transferred
343 ; This routine assumes CS == DS, and trashes most registers.
345 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
346 ; that is dead from that point; this saves space. However, please keep
347 ; the order to dst,src to keep things sane.
350 add eax,[bsHidden
] ; Add partition offset
351 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
353 .
jmp: jmp strict
short getlinsec_cbios
358 ; getlinsec implementation for EBIOS (EDD)
362 push bp ; Sectors left
364 call maxtrans
; Enforce maximum transfer size
365 movzx edi,bp ; Sectors we are about to read
382 mov ah,42h ; Extended Read
386 lea sp,[si+16] ; Remove DAPA
389 add eax,edi ; Advance sector pointer
390 sub bp,di ; Sectors left
391 shl di,SECTOR_SHIFT
; 512-byte sectors
392 add bx,di ; Advance buffer pointer
399 ; Some systems seem to get "stuck" in an error state when
400 ; using EBIOS. Doesn't happen when using CBIOS, which is
401 ; good, since some other systems get timeout failures
402 ; waiting for the floppy disk to spin up.
404 pushad ; Try resetting the device
409 loop .retry
; CX-- and jump if not zero
411 ;shr word [MaxTransfer],1 ; Reduce the transfer size
414 ; Total failure. Try falling back to CBIOS.
415 mov byte [getlinsec.
jmp+1],(getlinsec_cbios
-(getlinsec.
jmp+2))
416 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
419 ; ... fall through ...
424 ; getlinsec implementation for legacy CBIOS
433 movzx esi,word [bsSecPerTrack
]
434 movzx edi,word [bsHeads
]
436 ; Dividing by sectors to get (track,sector): we may have
437 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
441 xchg cx,dx ; CX <- sector index (0-based)
444 div edi ; Convert track to head/cyl
446 ; We should test this, but it doesn't fit...
451 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
452 ; BP = sectors to transfer, SI = bsSecPerTrack,
453 ; ES:BX = data target
456 call maxtrans
; Enforce maximum transfer size
458 ; Must not cross track boundaries, so BP <= SI-CX
465 shl ah,6 ; Because IBM was STOOPID
466 ; and thought 8 bits were enough
467 ; then thought 10 bits were enough...
468 inc cx ; Sector numbers are 1-based, sigh
473 xchg ax,bp ; Sector to transfer count
474 mov ah,02h ; Read sectors
482 movzx ecx,al ; ECX <- sectors transferred
483 shl ax,SECTOR_SHIFT
; Convert sectors in AL to bytes in AX
498 xchg ax,bp ; Sectors transferred <- 0
499 shr word [MaxTransfer
],1
501 ; Fall through to disk_error
504 ; kaboom: write a message and bail out.
510 mov sp,StackBuf
-4 ; Reset stack
511 mov ds,si ; Reset data segment
512 pop dword [fdctab
] ; Restore FDC table
513 .
patch: ; When we have full code, intercept here
516 ; Write error message, this assumes screen page 0
520 mov ah,0Eh
; Write to screen as TTY
521 mov bx,0007h ; Attribute
526 .
again: int 16h ; Wait for keypress
527 ; NB: replaced by int 18h if
528 ; chosen at install time..
529 int 19h ; And try once more to boot...
530 .
norge: jmp short .norge
; If int 19h returned; this is the end
533 ; Truncate BP to MaxTransfer
542 ; Error message on failure
544 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
546 ; This fails if the boot sector overflows
549 FirstSector
dd 0xDEADBEEF ; Location of sector 1
550 MaxTransfer
dw 0x007F ; Max transfer size
552 ; This field will be filled in 0xAA55 by the installer, but we abuse it
553 ; to house a pointer to the INT 16h instruction at
554 ; kaboom.again, which gets patched to INT 18h in RAID mode.
555 bootsignature
dw kaboom.again
-bootsec
558 ; ===========================================================================
560 ; ===========================================================================
561 ; Start of LDLINUX.SYS
562 ; ===========================================================================
566 syslinux_banner
db 0Dh, 0Ah
568 db version_str
, ' ', date
, ' ', 0
569 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
572 ldlinux_magic
dd LDLINUX_MAGIC
573 dd LDLINUX_MAGIC^HEXDATE
576 ; This area is patched by the installer. It is found by looking for
577 ; LDLINUX_MAGIC, plus 8 bytes.
580 LDLDwords
dw 0 ; Total dwords starting at ldlinux_sys,
582 LDLSectors
dw 0 ; Number of sectors, not including
583 ; bootsec & this sec, but including the two ADVs
584 CheckSum
dd 0 ; Checksum starting at ldlinux_sys
585 ; value = LDLINUX_MAGIC - [sum of dwords]
586 CurrentDir
dd 2 ; "Current" directory inode number
588 ; Space for up to 64 sectors, the theoretical maximum
589 SectorPtrs times
64 dd 0
593 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
594 ; instead of 0000:7C00 and the like. We don't want to add anything
595 ; more to the boot sector, so it is written to not assume a fixed
596 ; value in CS, but we don't want to deal with that anymore from now
603 ; Tell the user we got this far
605 mov si,syslinux_banner
609 ; Tell the user if we're using EBIOS or CBIOS
613 cmp byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
621 %define HAVE_BIOSNAME
1
626 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
627 ; sector again, though.
631 mov bx,7C00h
+2*SECTOR_SIZE
; Where we start loading
637 lodsd ; First sector of this chunk
645 inc edx ; Next linear sector
646 cmp [si],edx ; Does it match
647 jnz .chunk_ready
; If not, this is it
648 add si,4 ; If so, add sector to chunk
649 jmp short .make_chunk
660 ; All loaded up, verify that we got what we needed.
661 ; Note: the checksum field is embedded in the checksum region, so
662 ; by the time we get to the end it should all cancel out.
667 mov edx,-LDLINUX_MAGIC
673 and edx,edx ; Should be zero
674 jz all_read
; We're cool, go for it!
677 ; Uh-oh, something went bad...
679 mov si,checksumerr_msg
684 ; -----------------------------------------------------------------------------
685 ; Subroutines that have to be in the first sector
686 ; -----------------------------------------------------------------------------
690 ; writestr: write a null-terminated string to the console
691 ; This assumes we're on page 0. This is only used for early
692 ; messages, so it should be OK.
698 mov ah,0Eh
; Write to screen as TTY
699 mov bx,0007h ; Attribute
705 ; getlinsecsr: save registers, call getlinsec, restore registers
713 ; Checksum error message
715 checksumerr_msg
db ' Load error - ', 0 ; Boot failed appended
720 cbios_name
db 'CBIOS', 0
721 ebios_name
db 'EBIOS', 0
728 cmp word [Debug_Magic
],0D00Dh
733 rl_checkpt
equ $
; Must be <= 8000h
735 rl_checkpt_off
equ ($
-$$
)
737 %if rl_checkpt_off
> 400h
738 %error
"Sector 1 overflow"
742 ; ----------------------------------------------------------------------------
743 ; End of code and data that have to be in the first sector
744 ; ----------------------------------------------------------------------------
748 ; Let the user (and programmer!) know we got this far. This used to be
749 ; in Sector 1, but makes a lot more sense here.
755 ; Insane hack to expand the DOS superblock to dwords
761 mov cx,superinfo_size
765 stosd ; Store expanded word
767 stosd ; Store expanded byte
771 ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
774 mov eax,1024 >> SECTOR_SHIFT
779 ; Compute some values...
784 ; s_log_block_size = log2(blocksize) - 10
785 mov cl,[SuperBlock
+s_log_block_size
]
787 mov [ClustByteShift
],cl
795 mov [SecPerClust
],eax
799 add cl,SECTOR_SHIFT
-2 ; 4 bytes/pointer
801 mov [PtrsPerBlock1
],edx
803 mov [PtrsPerBlock2
],edx
806 ; Common initialization code
809 %include "cpuinit.inc"
812 ; Initialize the metadata cache
817 ; Now, everything is "up and running"... patch kaboom for more
818 ; verbosity and using the full screen system
821 mov dword [kaboom.patch
],0e9h
+((kaboom2
-(kaboom.patch
+3)) << 8)
824 ; Now we're all set to start with our *real* business. First load the
825 ; configuration file (if any) and parse it.
827 ; In previous versions I avoided using 32-bit registers because of a
828 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
829 ; random. I figure, though, that if there are any of those still left
830 ; they probably won't be trying to install Linux on them...
832 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
833 ; to take'm out. In fact, we may want to put them back if we're going
834 ; to boot ELKS at some point.
838 ; Load configuration file
841 mov si,config_name
; Save config file name
850 ; Now we have the config file open. Parse the config file and
851 ; run the user interface.
856 ; getlinsec_ext: same as getlinsec, except load any sector from the zero
857 ; block as all zeros; use to load any data derived
858 ; from an ext2 block pointer, i.e. anything *except the
865 cmp eax,[SecPerClust
]
866 jae getlinsec
; Nothing fancy
868 ; If we get here, at least part of what we want is in the
869 ; zero block. Zero one sector at a time and loop.
874 mov cx,SECTOR_SIZE
>> 2
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 ; EAX = file length in bytes
918 ; ThisInode = the first 128 bytes of the inode
922 ; Assumes CS == DS == ES.
924 open_inode.
allocate_failure:
934 jnz .allocate_failure
938 ; First, get the appropriate inode group and index
939 dec eax ; There is no inode 0
941 mov [bx+file_sector
],edx
942 div dword [SuperBlock
+s_inodes_per_group
]
943 ; EAX = inode group; EDX = inode within group
946 ; Now, we need the block group descriptor.
947 ; To get that, we first need the relevant descriptor block.
949 shl eax, ext2_group_desc_lg2size
; Get byte offset in desc table
951 div dword [ClustSize
]
952 ; eax = block #, edx = offset in block
953 add eax,dword [SuperBlock
+s_first_data_block
]
954 inc eax ; s_first_data_block+1
962 call getcachesector
; Get the group descriptor
964 mov esi,[gs:si+bg_inode_table
] ; Get inode table block #
965 pop eax ; Get inode within group
966 movzx edx, word [SuperBlock
+s_inode_size
]
968 ; edx:eax = byte offset in inode table
969 div dword [ClustSize
]
970 ; eax = block # versus inode table, edx = offset in block
972 shl eax,cl ; Turn into sector
976 mov [bx+file_in_sec
],eax
979 mov [bx+file_in_off
],dx
983 mov cx,EXT2_GOOD_OLD_INODE_SIZE
>> 2
987 mov ax,[ThisInode
+i_mode
]
988 mov [bx+file_mode
],ax
989 mov eax,[ThisInode
+i_size
]
990 mov [bx+file_bytesleft
],eax
992 and eax,eax ; ZF clear unless zero-length file
1001 ThisInode resb EXT2_GOOD_OLD_INODE_SIZE
; The most recently opened inode
1006 ; Deallocates a file structure (pointer in SI)
1012 mov dword [si],0 ; First dword == file_bytesleft
1018 ; Search the root directory for a pre-mangled filename in DS:DI.
1020 ; NOTE: This file considers finding a zero-length file an
1021 ; error. This is so we don't have to deal with that special
1022 ; case elsewhere in the program (most loops have the test
1028 ; DX:AX = EAX = file length in bytes
1032 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
1038 mov byte [SymlinkCtr
],MAX_SYMLINKS
1040 mov eax,[CurrentDir
]
1043 cmp byte [di],'/' ; Absolute filename?
1045 mov eax,EXT2_ROOT_INO
1050 ; At this point, EAX contains the directory inode,
1051 ; and DS:DI contains a pathname tail.
1053 push eax ; Save directory inode
1056 jz .missing
; If error, done
1058 mov cx,[si+file_mode
]
1059 shr cx,S_IFSHIFT
; Get file type
1064 add sp,4 ; Drop directory inode
1071 ; Otherwise, something bad...
1080 and eax,eax ; Set/clear ZF
1087 add sp,4 ; Drop directory inode
1094 cmp byte [di],0 ; End of path?
1095 je .done
; If so, done
1096 jmp .err
; Otherwise, error
1102 pop dword [ThisDir
] ; Remember what directory we're searching
1104 cmp byte [di],0 ; More path?
1105 je .err
; If not, bad
1107 .
skipslash: ; Skip redundant slashes
1114 mov cx,[SecPerClust
]
1124 pushf ; Save EOF flag
1125 push si ; Save filesystem pointer
1131 cmp dword [bx+d_inode
],0 ; Zero inode = void entry
1134 movzx cx,byte [bx+d_name_len
]
1140 add bx,[bx+d_rec_len
]
1146 jnc .readdir
; There is more
1147 jmp .err
; Otherwise badness...
1150 mov eax,[bx+d_inode
]
1152 ; Does this match the end of the requested filename?
1158 ; We found something; now we need to open the file
1160 pop bx ; Adjust stack (di)
1162 call close_file
; Close directory
1163 pop bx ; Adjust stack (flags)
1167 ; It's a symlink. We have to determine if it's a fast symlink
1168 ; (data stored in the inode) or not (data stored as a regular
1169 ; file.) Either which way, we start from the directory
1170 ; which we just visited if relative, or from the root directory
1171 ; if absolute, and append any remaining part of the path.
1174 dec byte [SymlinkCtr
]
1175 jz .err
; Too many symlink references
1177 cmp eax,SYMLINK_SECTORS
*SECTOR_SIZE
1178 jae .err
; Symlink too long
1180 ; Computation for fast symlink, as defined by ext2/3 spec
1182 cmp [ThisInode
+i_file_acl
],ecx
1183 setne cl ; ECX <- i_file_acl ? 1 : 0
1184 cmp [ThisInode
+i_blocks
],ecx
1187 ; It's a fast symlink
1189 call close_file
; We've got all we need
1190 mov si,ThisInode
+i_block
1193 mov di,SymlinkTmpBuf
1204 mov bp,SymlinkTmpBufEnd
1206 jc .err_noclose
; Buffer overflow
1208 ; Now copy it to the "real" buffer; we need to have
1209 ; two buffers so we avoid overwriting the tail on the
1211 mov si,SymlinkTmpBuf
1216 mov eax,[ThisDir
] ; Resume searching previous directory
1220 mov bx,SymlinkTmpBuf
1221 mov cx,SYMLINK_SECTORS
1223 ; The EOF closed the file
1225 mov si,di ; SI = filename tail
1226 mov di,SymlinkTmpBuf
1227 add di,ax ; AX = file length
1233 SymlinkBuf resb SYMLINK_SECTORS
*SECTOR_SIZE
+64
1234 SymlinkTmpBuf
equ trackbuf
1235 SymlinkTmpBufEnd
equ trackbuf
+SYMLINK_SECTORS
*SECTOR_SIZE
+64
1242 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1243 ; to by ES:DI; ends on encountering any whitespace.
1246 ; This verifies that a filename is < FILENAME_MAX characters,
1247 ; doesn't contain whitespace, zero-pads the output buffer,
1248 ; and removes redundant slashes,
1249 ; so "repe cmpsb" can do a compare, and the
1250 ; path-searching routine gets a bit of an easier job.
1252 ; FIX: we may want to support \-escapes here (and this would
1259 mov cx,FILENAME_MAX
-1
1264 cmp al,' ' ; If control or space, end
1266 cmp al,ah ; Repeated slash?
1273 .
mn_skip: loop .mn_loop
1275 cmp bx,di ; At the beginning of the buffer?
1277 cmp byte [di-1],'/' ; Terminal slash?
1279 .
mn_kill: dec di ; If so, remove it
1283 inc cx ; At least one null byte
1284 xor ax,ax ; Zero-fill name
1291 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1292 ; filename to the conventional representation. This is needed
1293 ; for the BOOT_IMAGE= parameter for the kernel.
1295 ; DS:SI -> input mangled file name
1296 ; ES:DI -> output buffer
1298 ; On return, DI points to the first byte after the output name,
1299 ; which is set to a null byte.
1301 unmangle_name: call strcpy
1302 dec di ; Point to final null byte
1307 ; kaboom2: once everything is loaded, replace the part of kaboom
1308 ; starting with "kaboom.patch" with this part
1311 mov si,err_bootfailed
1313 cmp byte [kaboom.again
+1],18h ; INT 18h version?
1317 int 19h ; And try once more to boot...
1318 .
norge: jmp short .norge
; If int 19h returned; this is the end
1322 .
noreg: jmp short .noreg
; Nynorsk
1326 ; linsector: Convert a linear sector index in a file to a linear sector number
1327 ; EAX -> linear sector number
1328 ; DS:SI -> open_file_t
1330 ; Returns next sector number in EAX; CF on EOF (not an error!)
1341 push eax ; Save sector index
1343 shr eax,cl ; Convert to block number
1345 mov eax,[si+file_in_sec
]
1347 call getcachesector
; Get inode
1348 add si,[bx+file_in_off
] ; Get *our* inode
1350 lea ebx,[i_block
+4*eax]
1351 cmp eax,EXT2_NDIR_BLOCKS
1353 mov ebx,i_block
+4*EXT2_IND_BLOCK
1354 sub eax,EXT2_NDIR_BLOCKS
1355 mov ebp,[PtrsPerBlock1
]
1358 mov ebx,i_block
+4*EXT2_DIND_BLOCK
1360 mov ebp,[PtrsPerBlock2
]
1363 mov ebx,i_block
+4*EXT2_TIND_BLOCK
1367 ; Triple indirect; eax contains the block no
1368 ; with respect to the start of the tind area;
1369 ; ebx contains the pointer to the tind block.
1371 div dword [PtrsPerBlock2
]
1372 ; EAX = which dind block, EDX = pointer within dind block
1374 shr eax,SECTOR_SHIFT
-2
1380 and bx,(SECTOR_SIZE
>> 2)-1
1382 mov eax,edx ; The ind2 code wants the remainder...
1385 ; Double indirect; eax contains the block no
1386 ; with respect to the start of the dind area;
1387 ; ebx contains the pointer to the dind block.
1389 div dword [PtrsPerBlock1
]
1390 ; EAX = which ind block, EDX = pointer within ind block
1392 shr eax,SECTOR_SHIFT
-2
1398 and bx,(SECTOR_SIZE
>> 2)-1
1400 mov eax,edx ; The int1 code wants the remainder...
1403 ; Single indirect; eax contains the block no
1404 ; with respect to the start of the ind area;
1405 ; ebx contains the pointer to the ind block.
1407 shr eax,SECTOR_SHIFT
-2
1413 and bx,(SECTOR_SIZE
>> 2)-1
1417 mov ebx,[gs:bx+si] ; Get the pointer
1419 pop eax ; Get the sector index again
1420 shl ebx,cl ; Convert block number to sector
1421 and eax,[ClustMask
] ; Add offset within block
1434 ; getfssec: Get multiple sectors from a file
1436 ; Same as above, except SI is a pointer to a open_file_t
1439 ; DS:SI -> Pointer to open_file_t
1440 ; CX -> Sector count (0FFFFh = until end of file)
1441 ; Must not exceed the ES segment
1442 ; Returns CF=1 on EOF (not necessarily error)
1443 ; On return ECX = number of bytes read
1444 ; All arguments are advanced to reflect data read.
1453 push ecx ; Sectors requested read
1454 mov eax,[si+file_bytesleft
]
1455 add eax,SECTOR_SIZE
-1
1456 shr eax,SECTOR_SHIFT
1457 cmp ecx,eax ; Number of sectors left
1462 mov eax,[si+file_sector
] ; Current start index
1465 push eax ; Fragment start sector
1467 xor ebp,ebp ; Fragment sector count
1475 add ax,bx ; Now DI = how far into 64K block we are
1476 not ax ; Bytes left in 64K block
1478 shr eax,SECTOR_SHIFT
; Sectors left in 64K block
1480 jnb .do_read
; Unless there is at least 1 more sector room...
1481 inc edi ; Sector index
1482 inc edx ; Linearly next sector
1489 pop eax ; Linear start sector
1495 add bx,bp ; Adjust buffer pointer
1497 add [si+file_sector
],ebp ; Next sector index
1502 pop ecx ; Sectors requested read
1503 shl ecx,SECTOR_SHIFT
1504 cmp ecx,[si+file_bytesleft
]
1506 mov ecx,[si+file_bytesleft
]
1507 .
noteof: sub [si+file_bytesleft
],ecx
1508 ; Did we run out of file?
1509 cmp dword [si+file_bytesleft
],1
1510 ; CF set if [SI] < 1, i.e. == 0
1517 ; -----------------------------------------------------------------------------
1519 ; -----------------------------------------------------------------------------
1521 %include "getc.inc" ; getc et al
1522 %include "conio.inc" ; Console I/O
1523 %include "plaincon.inc" ; writechr
1524 %include "writestr.inc" ; String output
1525 %include "configinit.inc" ; Initialize configuration
1526 %include "parseconfig.inc" ; High-level config file handling
1527 %include "parsecmd.inc" ; Low-level config file handling
1528 %include "bcopy32.inc" ; 32-bit bcopy
1529 %include "loadhigh.inc" ; Load a file into high memory
1530 %include "font.inc" ; VGA font stuff
1531 %include "graphics.inc" ; VGA graphics
1532 %include "highmem.inc" ; High memory sizing
1533 %include "strcpy.inc" ; strcpy()
1534 %include "strecpy.inc" ; strcpy with end pointer check
1535 %include "cache.inc" ; Metadata disk cache
1536 %include "adv.inc" ; Auxillary Data Vector
1538 ; -----------------------------------------------------------------------------
1539 ; Begin data section
1540 ; -----------------------------------------------------------------------------
1543 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
1545 err_bootfailed
db CR
, LF
, 'Boot failed: please change disks and press '
1546 db 'a key to continue.', CR
, LF
, 0
1547 config_name
db 'extlinux.conf',0 ; Unmangled form
1550 ; Command line options we'd like to take a look at
1552 ; mem= and vga= are handled as normal 32-bit integer values
1553 initrd_cmd
db 'initrd='
1554 initrd_cmd_len
equ 7
1557 ; Config file keyword table
1559 %include "keywords.inc"
1562 ; Extensions to search for (in *forward* order).
1565 exten_table: db '.cbt' ; COMBOOT (specific)
1566 db '.img' ; Disk image
1567 db '.bs', 0 ; Boot sector
1568 db '.com' ; COMBOOT (same as DOS)
1571 dd 0, 0 ; Need 8 null bytes here
1574 ; Misc initialized (data) variables
1576 %ifdef debug
; This code for debugging only
1577 debug_magic
dw 0D00Dh
; Debug code sentinel
1581 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1582 BufSafeBytes
dw trackbufsize
; = how many bytes?
1584 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1585 %error trackbufsize must be a multiple of SECTOR_SIZE