1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
6 ; A program to boot Linux kernels off an ext2/ext3 filesystem.
8 ; Copyright (C) 1994-2006 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
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 trackbufsize
equ 8192
110 trackbuf resb trackbufsize
; Track buffer goes here
111 getcbuf resb trackbufsize
115 SuperBlock resb
1024 ; ext2 superblock
116 SuperInfo resq
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 DriveNumber resb
1 ; BIOS drive number
123 ClustShift resb
1 ; Shift count for sectors/cluster
124 ClustByteShift resb
1 ; Shift count for bytes/cluster
126 alignb open_file_t_size
127 Files resb MAX_OPEN
*open_file_t_size
130 ; Constants for the xfer_buf_seg
132 ; The xfer_buf_seg is also used to store message file buffers. We
133 ; need two trackbuffers (text and graphics), plus a work buffer
134 ; for the graphics decompressor.
136 xbs_textbuf
equ 0 ; Also hard-coded, do not change
137 xbs_vgabuf
equ trackbufsize
138 xbs_vgatmpbuf
equ 2*trackbufsize
143 ; Some of the things that have to be saved very early are saved
144 ; "close" to the initial stack pointer offset, in order to
145 ; reduce the code size...
147 StackBuf
equ $
-44-32 ; Start the stack here (grow down - 4K)
148 PartInfo
equ StackBuf
; Saved partition table entry
149 FloppyTable
equ PartInfo
+16 ; Floppy info table (must follow PartInfo)
150 OrigFDCTabPtr
equ StackBuf
-4 ; The high dword on the stack
153 ; Primary entry point. Tempting as though it may be, we can't put the
154 ; initial "cli" here; the jmp opcode in the first byte is part of the
155 ; "magic number" (using the term very loosely) for the DOS superblock.
158 jmp short start
; 2 bytes
161 ; "Superblock" follows -- it's in the boot sector, so it's already
162 ; loaded and ready for us
164 bsOemName
db 'EXTLINUX' ; The SYS command sets this, so...
166 ; These are the fields we actually care about. We end up expanding them
167 ; all to dword size early in the code, so generate labels for both
168 ; the expanded and unexpanded versions.
171 bx %+ %1 equ SuperInfo
+($
-superblock
)*8+4
176 bx %+ %1 equ SuperInfo
+($
-superblock
)*8
181 bx %+ %1 equ $
; no expansion for dwords
196 superinfo_size
equ ($
-superblock
)-1 ; How much to expand
200 ; This is as far as FAT12/16 and FAT32 are consistent
202 zb
54 ; FAT12/16 need 26 more bytes,
203 ; FAT32 need 54 more bytes
204 superblock_len
equ $
-superblock
207 ; Note we don't check the constraints above now; we did that at install
211 cli ; No interrupts yet, please
218 mov sp,StackBuf
; Just below BSS
221 ; DS:SI may contain a partition table entry. Preserve it for us.
223 mov cx,8 ; Save partition info
227 mov ds,ax ; Now we can initialize DS...
230 ; Now sautee the BIOS floppy info block to that it will support decent-
231 ; size transfers; the floppy block is 11 bytes and is stored in the
232 ; INT 1Eh vector (brilliant waste of resources, eh?)
234 ; Of course, if BIOSes had been properly programmed, we wouldn't have
235 ; had to waste precious space with this code.
238 lfs si,[bx] ; FS:SI -> original fdctab
239 push fs ; Save on stack in case we need to bail
242 ; Save the old fdctab even if hard disk so the stack layout
243 ; is the same. The instructions above do not change the flags
244 mov [DriveNumber
],dl ; Save drive number in DL
245 and dl,dl ; If floppy disk (00-7F), assume no
250 mov cl,6 ; 12 bytes (CX == 0)
251 ; es:di -> FloppyTable already
252 ; This should be safe to do now, interrupts are off...
253 mov [bx],di ; FloppyTable
254 mov [bx+2],ax ; Segment 0
255 fs rep movsw ; Faster to move words
256 mov cl,[bsSecPerTrack
] ; Patch the sector count
259 int 13h ; Some BIOSes need this
261 jmp short not_harddisk
263 ; The drive number and possibly partition information was passed to us
264 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
265 ; trust that rather than what the superblock contains.
267 ; Would it be better to zero out bsHidden if we don't have a partition table?
269 ; Note: di points to beyond the end of PartInfo
272 test byte [di-16],7Fh
; Sanity check: "active flag" should
273 jnz no_partition
; be 00 or 80
274 mov eax,[di-8] ; Partition offset (dword)
278 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
279 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
280 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
281 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
283 ; DL == drive # still
290 inc dx ; Contains # of heads - 1
293 mov [bsSecPerTrack
],cx
297 ; Ready to enable interrupts, captain
302 ; Do we have EBIOS (EDD)?
306 mov ah,41h ; EDD existence query
312 test cl,1 ; Extended disk access functionality set
315 ; We have EDD support...
317 mov byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
321 ; Load the first sector of LDLINUX.SYS; this used to be all proper
322 ; with parsing the superblock and root directory; it doesn't fit
323 ; together with EBIOS support, unfortunately.
325 mov eax,[FirstSector
] ; Sector start
326 mov bx,ldlinux_sys
; Where to load it
329 ; Some modicum of integrity checking
330 cmp dword [ldlinux_magic
+4],LDLINUX_MAGIC^HEXDATE
337 ; getonesec: get one disk sector
340 mov bp,1 ; One sector
344 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
345 ; number in EAX into the buffer at ES:BX. We try to optimize
346 ; by loading up to a whole track at a time, but the user
347 ; is responsible for not crossing a 64K boundary.
348 ; (Yes, BP is weird for a count, but it was available...)
350 ; On return, BX points to the first byte after the transferred
353 ; This routine assumes CS == DS, and trashes most registers.
355 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
356 ; that is dead from that point; this saves space. However, please keep
357 ; the order to dst,src to keep things sane.
360 add eax,[bsHidden
] ; Add partition offset
361 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
363 .
jmp: jmp strict
short getlinsec_cbios
368 ; getlinsec implementation for EBIOS (EDD)
372 push bp ; Sectors left
374 call maxtrans
; Enforce maximum transfer size
375 movzx edi,bp ; Sectors we are about to read
392 mov ah,42h ; Extended Read
396 lea sp,[si+16] ; Remove DAPA
399 add eax,edi ; Advance sector pointer
400 sub bp,di ; Sectors left
401 shl di,SECTOR_SHIFT
; 512-byte sectors
402 add bx,di ; Advance buffer pointer
409 ; Some systems seem to get "stuck" in an error state when
410 ; using EBIOS. Doesn't happen when using CBIOS, which is
411 ; good, since some other systems get timeout failures
412 ; waiting for the floppy disk to spin up.
414 pushad ; Try resetting the device
419 loop .retry
; CX-- and jump if not zero
421 ;shr word [MaxTransfer],1 ; Reduce the transfer size
424 ; Total failure. Try falling back to CBIOS.
425 mov byte [getlinsec.
jmp+1],(getlinsec_cbios
-(getlinsec.
jmp+2))
426 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
429 ; ... fall through ...
434 ; getlinsec implementation for legacy CBIOS
443 movzx esi,word [bsSecPerTrack
]
444 movzx edi,word [bsHeads
]
446 ; Dividing by sectors to get (track,sector): we may have
447 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
451 xchg cx,dx ; CX <- sector index (0-based)
454 div edi ; Convert track to head/cyl
456 ; We should test this, but it doesn't fit...
461 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
462 ; BP = sectors to transfer, SI = bsSecPerTrack,
463 ; ES:BX = data target
466 call maxtrans
; Enforce maximum transfer size
468 ; Must not cross track boundaries, so BP <= SI-CX
475 shl ah,6 ; Because IBM was STOOPID
476 ; and thought 8 bits were enough
477 ; then thought 10 bits were enough...
478 inc cx ; Sector numbers are 1-based, sigh
483 xchg ax,bp ; Sector to transfer count
484 mov ah,02h ; Read sectors
492 movzx ecx,al ; ECX <- sectors transferred
493 shl ax,SECTOR_SHIFT
; Convert sectors in AL to bytes in AX
508 xchg ax,bp ; Sectors transferred <- 0
509 shr word [MaxTransfer
],1
511 ; Fall through to disk_error
514 ; kaboom: write a message and bail out.
520 mov sp,StackBuf
-4 ; Reset stack
521 mov ds,si ; Reset data segment
522 pop dword [fdctab
] ; Restore FDC table
523 .
patch: ; When we have full code, intercept here
526 ; Write error message, this assumes screen page 0
530 mov ah,0Eh
; Write to screen as TTY
531 mov bx,0007h ; Attribute
536 int 16h ; Wait for keypress
537 int 19h ; And try once more to boot...
538 .
norge: jmp short .norge
; If int 19h returned; this is the end
541 ; Truncate BP to MaxTransfer
550 ; Error message on failure
552 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
554 ; This fails if the boot sector overflows
557 FirstSector
dd 0xDEADBEEF ; Location of sector 1
558 MaxTransfer
dw 0x007F ; Max transfer size
559 bootsignature
dw 0AA55h
562 ; ===========================================================================
564 ; ===========================================================================
565 ; Start of LDLINUX.SYS
566 ; ===========================================================================
570 syslinux_banner
db 0Dh, 0Ah
572 db version_str
, ' ', date
, ' ', 0
573 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
576 ldlinux_magic
dd LDLINUX_MAGIC
577 dd LDLINUX_MAGIC^HEXDATE
580 ; This area is patched by the installer. It is found by looking for
581 ; LDLINUX_MAGIC, plus 8 bytes.
584 LDLDwords
dw 0 ; Total dwords starting at ldlinux_sys
585 LDLSectors
dw 0 ; Number of sectors - (bootsec+this sec)
586 CheckSum
dd 0 ; Checksum starting at ldlinux_sys
587 ; value = LDLINUX_MAGIC - [sum of dwords]
588 CurrentDir
dd 2 ; "Current" directory inode number
590 ; Space for up to 64 sectors, the theoretical maximum
591 SectorPtrs times
64 dd 0
595 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
596 ; instead of 0000:7C00 and the like. We don't want to add anything
597 ; more to the boot sector, so it is written to not assume a fixed
598 ; value in CS, but we don't want to deal with that anymore from now
605 ; Tell the user we got this far
607 mov si,syslinux_banner
611 ; Tell the user if we're using EBIOS or CBIOS
615 cmp byte [getlinsec.
jmp+1],(getlinsec_ebios
-(getlinsec.
jmp+2))
623 %define HAVE_BIOSNAME
1
628 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
629 ; sector again, though.
633 mov bx,7C00h
+2*SECTOR_SIZE
; Where we start loading
639 lodsd ; First sector of this chunk
647 inc edx ; Next linear sector
648 cmp [si],edx ; Does it match
649 jnz .chunk_ready
; If not, this is it
650 add si,4 ; If so, add sector to chunk
651 jmp short .make_chunk
662 ; All loaded up, verify that we got what we needed.
663 ; Note: the checksum field is embedded in the checksum region, so
664 ; by the time we get to the end it should all cancel out.
669 mov edx,-LDLINUX_MAGIC
675 and edx,edx ; Should be zero
676 jz all_read
; We're cool, go for it!
679 ; Uh-oh, something went bad...
681 mov si,checksumerr_msg
686 ; -----------------------------------------------------------------------------
687 ; Subroutines that have to be in the first sector
688 ; -----------------------------------------------------------------------------
692 ; writestr: write a null-terminated string to the console
693 ; This assumes we're on page 0. This is only used for early
694 ; messages, so it should be OK.
700 mov ah,0Eh
; Write to screen as TTY
701 mov bx,0007h ; Attribute
707 ; getlinsecsr: save registers, call getlinsec, restore registers
715 ; Checksum error message
717 checksumerr_msg
db ' Load error - ', 0 ; Boot failed appended
722 cbios_name
db 'CBIOS', 0
723 ebios_name
db 'EBIOS', 0
730 cmp word [Debug_Magic
],0D00Dh
735 rl_checkpt
equ $
; Must be <= 8000h
737 rl_checkpt_off
equ ($
-$$
)
739 %if rl_checkpt_off
> 400h
740 %error
"Sector 1 overflow"
744 ; ----------------------------------------------------------------------------
745 ; End of code and data that have to be in the first sector
746 ; ----------------------------------------------------------------------------
750 ; Let the user (and programmer!) know we got this far. This used to be
751 ; in Sector 1, but makes a lot more sense here.
757 ; Insane hack to expand the DOS superblock to dwords
763 mov cx,superinfo_size
767 stosd ; Store expanded word
769 stosd ; Store expanded byte
773 ; Load the real (ext2) superblock; 1024 bytes long at offset 1024
776 mov eax,1024 >> SECTOR_SHIFT
781 ; Compute some values...
786 ; s_log_block_size = log2(blocksize) - 10
787 mov cl,[SuperBlock
+s_log_block_size
]
789 mov [ClustByteShift
],cl
797 mov [SecPerClust
],eax
801 add cl,SECTOR_SHIFT
-2 ; 4 bytes/pointer
803 mov [PtrsPerBlock1
],edx
805 mov [PtrsPerBlock2
],edx
808 ; Common initialization code
811 %include "cpuinit.inc"
814 ; Initialize the metadata cache
819 ; Now, everything is "up and running"... patch kaboom for more
820 ; verbosity and using the full screen system
823 mov dword [kaboom.patch
],0e9h
+((kaboom2
-(kaboom.patch
+3)) << 8)
826 ; Now we're all set to start with our *real* business. First load the
827 ; configuration file (if any) and parse it.
829 ; In previous versions I avoided using 32-bit registers because of a
830 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
831 ; random. I figure, though, that if there are any of those still left
832 ; they probably won't be trying to install Linux on them...
834 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
835 ; to take'm out. In fact, we may want to put them back if we're going
836 ; to boot ELKS at some point.
840 ; Load configuration file
848 ; Now we have the config file open. Parse the config file and
849 ; run the user interface.
854 ; Linux kernel loading code is common.
856 %include "runkernel.inc"
859 ; COMBOOT-loading code
861 %include "comboot.inc"
863 %include "cmdline.inc"
866 ; Boot sector loading code
868 %include "bootsect.inc"
872 ; getlinsec_ext: same as getlinsec, except load any sector from the zero
873 ; block as all zeros; use to load any data derived
874 ; from an ext2 block pointer, i.e. anything *except the
881 cmp eax,[SecPerClust
]
882 jae getlinsec
; Nothing fancy
884 ; If we get here, at least part of what we want is in the
885 ; zero block. Zero one sector at a time and loop.
890 mov cx,SECTOR_SIZE
>> 2
906 ; allocate_file: Allocate a file structure
919 .
check: cmp dword [bx], byte 0
921 add bx,open_file_t_size
; ZF = 0
923 ; ZF = 0 if we fell out of the loop
928 ; Open a file indicated by an inode number in EAX
930 ; NOTE: This file considers finding a zero-length file an
931 ; error. This is so we don't have to deal with that special
932 ; case elsewhere in the program (most loops have the test
938 ; DX:AX = EAX = file length in bytes
939 ; ThisInode = the first 128 bytes of the inode
943 ; Assumes CS == DS == ES.
945 open_inode.
allocate_failure:
955 jnz .allocate_failure
959 ; First, get the appropriate inode group and index
960 dec eax ; There is no inode 0
962 mov [bx+file_sector
],edx
963 div dword [SuperBlock
+s_inodes_per_group
]
964 ; EAX = inode group; EDX = inode within group
967 ; Now, we need the block group descriptor.
968 ; To get that, we first need the relevant descriptor block.
970 shl eax, ext2_group_desc_lg2size
; Get byte offset in desc table
972 div dword [ClustSize
]
973 ; eax = block #, edx = offset in block
974 add eax,dword [SuperBlock
+s_first_data_block
]
975 inc eax ; s_first_data_block+1
983 call getcachesector
; Get the group descriptor
985 mov esi,[gs:si+bg_inode_table
] ; Get inode table block #
986 pop eax ; Get inode within group
987 movzx edx, word [SuperBlock
+s_inode_size
]
989 ; edx:eax = byte offset in inode table
990 div dword [ClustSize
]
991 ; eax = block # versus inode table, edx = offset in block
993 shl eax,cl ; Turn into sector
997 mov [bx+file_in_sec
],eax
1000 mov [bx+file_in_off
],dx
1004 mov cx,EXT2_GOOD_OLD_INODE_SIZE
>> 2
1008 mov ax,[ThisInode
+i_mode
]
1009 mov [bx+file_mode
],ax
1010 mov eax,[ThisInode
+i_size
]
1012 add eax,SECTOR_SIZE
-1
1013 shr eax,SECTOR_SHIFT
1014 mov [bx+file_left
],eax
1018 shr edx,16 ; 16-bitism, sigh
1019 and eax,eax ; ZF clear unless zero-length file
1028 ThisInode resb EXT2_GOOD_OLD_INODE_SIZE
; The most recently opened inode
1033 ; Deallocates a file structure (pointer in SI)
1037 mov dword [si],0 ; First dword == file_left
1042 ; Search the root directory for a pre-mangled filename in DS:DI.
1044 ; NOTE: This file considers finding a zero-length file an
1045 ; error. This is so we don't have to deal with that special
1046 ; case elsewhere in the program (most loops have the test
1052 ; DX:AX = EAX = file length in bytes
1056 ; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
1062 mov byte [SymlinkCtr
],MAX_SYMLINKS
1064 mov eax,[CurrentDir
]
1067 cmp byte [di],'/' ; Absolute filename?
1069 mov eax,EXT2_ROOT_INO
1074 ; At this point, EAX contains the directory inode,
1075 ; and DS:DI contains a pathname tail.
1077 push eax ; Save directory inode
1080 jz .done
; If error, done
1082 mov cx,[si+file_mode
]
1083 shr cx,S_IFSHIFT
; Get file type
1088 add sp,4 ; Drop directory inode
1095 ; Otherwise, something bad...
1104 and eax,eax ; Set/clear ZF
1114 cmp byte [di],0 ; End of path?
1115 je .done
; If so, done
1116 jmp .err
; Otherwise, error
1122 pop dword [ThisDir
] ; Remember what directory we're searching
1124 cmp byte [di],0 ; More path?
1125 je .err
; If not, bad
1127 .
skipslash: ; Skip redundant slashes
1136 mov cx,[SecPerClust
]
1139 pushf ; Save EOF flag
1140 push si ; Save filesystem pointer
1142 cmp dword [bx+d_inode
],0
1146 movzx cx,byte [bx+d_name_len
]
1153 add bx,[bx+d_rec_len
]
1159 jnc .readdir
; There is more
1160 jmp .err
; Otherwise badness...
1163 mov eax,[bx+d_inode
]
1165 ; Does this match the end of the requested filename?
1171 ; We found something; now we need to open the file
1173 pop bx ; Adjust stack (di)
1175 call close
; Close directory
1176 pop bx ; Adjust stack (flags)
1180 ; It's a symlink. We have to determine if it's a fast symlink
1181 ; (data stored in the inode) or not (data stored as a regular
1182 ; file.) Either which way, we start from the directory
1183 ; which we just visited if relative, or from the root directory
1184 ; if absolute, and append any remaining part of the path.
1187 dec byte [SymlinkCtr
]
1188 jz .err
; Too many symlink references
1190 cmp eax,SYMLINK_SECTORS
*SECTOR_SIZE
1191 jae .err
; Symlink too long
1193 ; Computation for fast symlink, as defined by ext2/3 spec
1195 cmp [ThisInode
+i_file_acl
],ecx
1196 setne cl ; ECX <- i_file_acl ? 1 : 0
1197 cmp [ThisInode
+i_blocks
],ecx
1200 ; It's a fast symlink
1202 call close
; We've got all we need
1203 mov si,ThisInode
+i_block
1206 mov di,SymlinkTmpBuf
1217 mov bp,SymlinkTmpBufEnd
1219 jc .err_noclose
; Buffer overflow
1221 ; Now copy it to the "real" buffer; we need to have
1222 ; two buffers so we avoid overwriting the tail on the
1224 mov si,SymlinkTmpBuf
1229 mov eax,[ThisDir
] ; Resume searching previous directory
1233 mov bx,SymlinkTmpBuf
1234 mov cx,SYMLINK_SECTORS
1236 ; The EOF closed the file
1238 mov si,di ; SI = filename tail
1239 mov di,SymlinkTmpBuf
1240 add di,ax ; AX = file length
1246 SymlinkBuf resb SYMLINK_SECTORS
*SECTOR_SIZE
+64
1247 SymlinkTmpBuf
equ trackbuf
1248 SymlinkTmpBufEnd
equ trackbuf
+SYMLINK_SECTORS
*SECTOR_SIZE
+64
1254 ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1255 ; to by ES:DI; ends on encountering any whitespace.
1257 ; This verifies that a filename is < FILENAME_MAX characters,
1258 ; doesn't contain whitespace, zero-pads the output buffer,
1259 ; and removes redundant slashes,
1260 ; so "repe cmpsb" can do a compare, and the
1261 ; path-searching routine gets a bit of an easier job.
1263 ; FIX: we may want to support \-escapes here (and this would
1269 mov cx,FILENAME_MAX
-1
1274 cmp al,' ' ; If control or space, end
1276 cmp al,ah ; Repeated slash?
1283 .
mn_skip: loop .mn_loop
1285 cmp bx,di ; At the beginning of the buffer?
1287 cmp byte [di-1],'/' ; Terminal slash?
1289 .
mn_kill: dec di ; If so, remove it
1293 inc cx ; At least one null byte
1294 xor ax,ax ; Zero-fill name
1300 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1301 ; filename to the conventional representation. This is needed
1302 ; for the BOOT_IMAGE= parameter for the kernel.
1303 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1304 ; known to be shorter.
1306 ; DS:SI -> input mangled file name
1307 ; ES:DI -> output buffer
1309 ; On return, DI points to the first byte after the output name,
1310 ; which is set to a null byte.
1312 unmangle_name: call strcpy
1313 dec di ; Point to final null byte
1318 ; kaboom2: once everything is loaded, replace the part of kaboom
1319 ; starting with "kaboom.patch" with this part
1322 mov si,err_bootfailed
1326 int 19h ; And try once more to boot...
1327 .
norge: jmp short .norge
; If int 19h returned; this is the end
1331 ; linsector: Convert a linear sector index in a file to a linear sector number
1332 ; EAX -> linear sector number
1333 ; DS:SI -> open_file_t
1335 ; Returns next sector number in EAX; CF on EOF (not an error!)
1346 push eax ; Save sector index
1348 shr eax,cl ; Convert to block number
1350 mov eax,[si+file_in_sec
]
1352 call getcachesector
; Get inode
1353 add si,[bx+file_in_off
] ; Get *our* inode
1355 lea ebx,[i_block
+4*eax]
1356 cmp eax,EXT2_NDIR_BLOCKS
1358 mov ebx,i_block
+4*EXT2_IND_BLOCK
1359 sub eax,EXT2_NDIR_BLOCKS
1360 mov ebp,[PtrsPerBlock1
]
1363 mov ebx,i_block
+4*EXT2_DIND_BLOCK
1365 mov ebp,[PtrsPerBlock2
]
1368 mov ebx,i_block
+4*EXT2_TIND_BLOCK
1372 ; Triple indirect; eax contains the block no
1373 ; with respect to the start of the tind area;
1374 ; ebx contains the pointer to the tind block.
1376 div dword [PtrsPerBlock2
]
1377 ; EAX = which dind block, EDX = pointer within dind block
1379 shr eax,SECTOR_SHIFT
-2
1385 and bx,(SECTOR_SIZE
>> 2)-1
1387 mov eax,edx ; The ind2 code wants the remainder...
1390 ; Double indirect; eax contains the block no
1391 ; with respect to the start of the dind area;
1392 ; ebx contains the pointer to the dind block.
1394 div dword [PtrsPerBlock1
]
1395 ; EAX = which ind block, EDX = pointer within ind block
1397 shr eax,SECTOR_SHIFT
-2
1403 and bx,(SECTOR_SIZE
>> 2)-1
1405 mov eax,edx ; The int1 code wants the remainder...
1408 ; Single indirect; eax contains the block no
1409 ; with respect to the start of the ind area;
1410 ; ebx contains the pointer to the ind block.
1412 shr eax,SECTOR_SHIFT
-2
1418 and bx,(SECTOR_SIZE
>> 2)-1
1422 mov ebx,[gs:bx+si] ; Get the pointer
1424 pop eax ; Get the sector index again
1425 shl ebx,cl ; Convert block number to sector
1426 and eax,[ClustMask
] ; Add offset within block
1439 ; getfssec: Get multiple sectors from a file
1441 ; Same as above, except SI is a pointer to a open_file_t
1444 ; DS:SI -> Pointer to open_file_t
1445 ; CX -> Sector count (0FFFFh = until end of file)
1446 ; Must not exceed the ES segment
1447 ; Returns CF=1 on EOF (not necessarily error)
1448 ; All arguments are advanced to reflect data read.
1457 cmp ecx,[si] ; 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
1498 sub [si],ebp ; Sectors consumed
1503 cmp dword [si],1 ; Did we run out of file?
1504 ; CF set if [SI] < 1, i.e. == 0
1511 ; -----------------------------------------------------------------------------
1513 ; -----------------------------------------------------------------------------
1515 %include "getc.inc" ; getc et al
1516 %include "conio.inc" ; Console I/O
1517 %include "plaincon.inc" ; writechr
1518 %include "writestr.inc" ; String output
1519 %include "parseconfig.inc" ; High-level config file handling
1520 %include "parsecmd.inc" ; Low-level config file handling
1521 %include "bcopy32.inc" ; 32-bit bcopy
1522 %include "loadhigh.inc" ; Load a file into high memory
1523 %include "font.inc" ; VGA font stuff
1524 %include "graphics.inc" ; VGA graphics
1525 %include "highmem.inc" ; High memory sizing
1526 %include "strcpy.inc" ; strcpy()
1527 %include "strecpy.inc" ; strcpy with end pointer check
1528 %include "cache.inc"
1530 ; -----------------------------------------------------------------------------
1531 ; Begin data section
1532 ; -----------------------------------------------------------------------------
1535 copyright_str
db ' Copyright (C) 1994-', year
, ' H. Peter Anvin'
1537 boot_prompt
db 'boot: ', 0
1538 wipe_char
db BS
, ' ', BS
, 0
1539 err_notfound
db 'Could not find kernel image: ',0
1540 err_notkernel
db CR
, LF
, 'Invalid or corrupt kernel image.', CR
, LF
, 0
1541 err_noram
db 'It appears your computer has less than '
1543 db 'K of low ("DOS")'
1545 db 'RAM. Linux needs at least this amount to boot. If you get'
1547 db 'this message in error, hold down the Ctrl key while'
1549 db 'booting, and I will take your word for it.', CR
, LF
, 0
1550 err_badcfg
db 'Unknown keyword in extlinux.conf.', CR
, LF
, 0
1551 err_noparm
db 'Missing parameter in extlinux.conf.', CR
, LF
, 0
1552 err_noinitrd
db CR
, LF
, 'Could not find ramdisk image: ', 0
1553 err_nohighmem
db 'Not enough memory to load specified kernel.', CR
, LF
, 0
1554 err_highload
db CR
, LF
, 'Kernel transfer failure.', CR
, LF
, 0
1555 err_oldkernel
db 'Cannot load a ramdisk with an old kernel image.'
1557 err_notdos
db ': attempted DOS system call', CR
, LF
, 0
1558 err_comlarge
db 'COMBOOT image too large.', CR
, LF
, 0
1559 err_bssimage
db 'BSS images not supported.', CR
, LF
, 0
1560 err_a20
db CR
, LF
, 'A20 gate not responding!', CR
, LF
, 0
1561 err_bootfailed
db CR
, LF
, 'Boot failed: please change disks and press '
1562 db 'a key to continue.', CR
, LF
, 0
1563 ready_msg
db 'Ready.', CR
, LF
, 0
1564 crlfloading_msg
db CR
, LF
1565 loading_msg
db 'Loading ', 0
1568 aborted_msg
db ' aborted.' ; Fall through to crlf_msg!
1571 crff_msg
db CR
, FF
, 0
1572 ConfigName
db 'extlinux.conf',0 ; Unmangled form
1575 ; Command line options we'd like to take a look at
1577 ; mem= and vga= are handled as normal 32-bit integer values
1578 initrd_cmd
db 'initrd='
1579 initrd_cmd_len
equ 7
1582 ; Config file keyword table
1584 %include "keywords.inc"
1587 ; Extensions to search for (in *forward* order).
1590 exten_table: db '.cbt' ; COMBOOT (specific)
1591 db '.img' ; Disk image
1592 db '.bs', 0 ; Boot sector
1593 db '.com' ; COMBOOT (same as DOS)
1596 dd 0, 0 ; Need 8 null bytes here
1599 ; Misc initialized (data) variables
1601 %ifdef debug
; This code for debugging only
1602 debug_magic
dw 0D00Dh
; Debug code sentinel
1606 BufSafe
dw trackbufsize
/SECTOR_SIZE
; Clusters we can load into trackbuf
1607 BufSafeSec
dw trackbufsize
/SECTOR_SIZE
; = how many sectors?
1608 BufSafeBytes
dw trackbufsize
; = how many bytes?
1609 EndOfGetCBuf
dw getcbuf
+trackbufsize
; = getcbuf+BufSafeBytes
1611 %if
( trackbufsize
% SECTOR_SIZE
) != 0
1612 %error trackbufsize must be a multiple of SECTOR_SIZE