📄 extlinux.asm
字号:
add sp,4 ; Drop directory inode cmp cx,T_IFREG je .file cmp cx,T_IFLNK je .symlink ; Otherwise, something bad....err: call close.err_noclose: xor eax,eax xor si,si cwd ; DX <- 0.done: and eax,eax ; Set/clear ZF pop bp pop cx pop bx ret ; ; It's a file. ;.file: cmp byte [di],0 ; End of path? je .done ; If so, done jmp .err ; Otherwise, error ; ; It's a directory. ;.directory: pop dword [ThisDir] ; Remember what directory we're searching cmp byte [di],0 ; More path? je .err ; If not, bad .skipslash: ; Skip redundant slashes cmp byte [di],'/' jne .readdir inc di jmp .skipslash.readdir: mov bx,trackbuf push bx mov cx,[SecPerClust] call getfssec pop bx pushf ; Save EOF flag push si ; Save filesystem pointer.getent: cmp dword [bx+d_inode],0 je .endblock push di movzx cx,byte [bx+d_name_len] lea si,[bx+d_name] repe cmpsb je .maybe.nope: pop di add bx,[bx+d_rec_len] jmp .getent.endblock: pop si popf jnc .readdir ; There is more jmp .err ; Otherwise badness....maybe: mov eax,[bx+d_inode] ; Does this match the end of the requested filename? cmp byte [di],0 je .finish cmp byte [di],'/' jne .nope ; We found something; now we need to open the file.finish: pop bx ; Adjust stack (di) pop si call close ; Close directory pop bx ; Adjust stack (flags) jmp .open ; ; It's a symlink. We have to determine if it's a fast symlink ; (data stored in the inode) or not (data stored as a regular ; file.) Either which way, we start from the directory ; which we just visited if relative, or from the root directory ; if absolute, and append any remaining part of the path. ;.symlink: dec byte [SymlinkCtr] jz .err ; Too many symlink references cmp eax,SYMLINK_SECTORS*SECTOR_SIZE jae .err ; Symlink too long ; Computation for fast symlink, as defined by ext2/3 spec xor ecx,ecx cmp [ThisInode+i_file_acl],ecx setne cl ; ECX <- i_file_acl ? 1 : 0 cmp [ThisInode+i_blocks],ecx jne .slow_symlink ; It's a fast symlink.fast_symlink: call close ; We've got all we need mov si,ThisInode+i_block push di mov di,SymlinkTmpBuf mov ecx,eax rep movsb pop si.symlink_finish: cmp byte [si],0 je .no_slash mov al,'/' stosb.no_slash: mov bp,SymlinkTmpBufEnd call strecpy jc .err_noclose ; Buffer overflow ; Now copy it to the "real" buffer; we need to have ; two buffers so we avoid overwriting the tail on the ; next copy mov si,SymlinkTmpBuf mov di,SymlinkBuf push di call strcpy pop di mov eax,[ThisDir] ; Resume searching previous directory jmp .begin_path.slow_symlink: mov bx,SymlinkTmpBuf mov cx,SYMLINK_SECTORS call getfssec ; The EOF closed the file mov si,di ; SI = filename tail mov di,SymlinkTmpBuf add di,ax ; AX = file length jmp .symlink_finish section .bss alignb 4SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64SymlinkTmpBuf equ trackbufSymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64ThisDir resd 1SymlinkCtr resb 1 section .text;; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed; to by ES:DI; ends on encountering any whitespace.;; This verifies that a filename is < FILENAME_MAX characters,; doesn't contain whitespace, zero-pads the output buffer,; and removes redundant slashes,; so "repe cmpsb" can do a compare, and the; path-searching routine gets a bit of an easier job.;; FIX: we may want to support \-escapes here (and this would; be the place.); mangle_name: push bx xor ax,ax mov cx,FILENAME_MAX-1 mov bx,di.mn_loop: lodsb cmp al,' ' ; If control or space, end jna .mn_end cmp al,ah ; Repeated slash? je .mn_skip xor ah,ah cmp al,'/' jne .mn_ok mov ah,al.mn_ok stosb.mn_skip: loop .mn_loop.mn_end: cmp bx,di ; At the beginning of the buffer? jbe .mn_zero cmp byte [di-1],'/' ; Terminal slash? jne .mn_zero.mn_kill: dec di ; If so, remove it inc cx jmp short .mn_end.mn_zero: inc cx ; At least one null byte xor ax,ax ; Zero-fill name rep stosb pop bx ret ; Done;; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled; filename to the conventional representation. This is needed; for the BOOT_IMAGE= parameter for the kernel.; NOTE: A 13-byte buffer is mandatory, even if the string is; known to be shorter.;; DS:SI -> input mangled file name; ES:DI -> output buffer;; On return, DI points to the first byte after the output name,; which is set to a null byte.;unmangle_name: call strcpy dec di ; Point to final null byte ret;; writechr: Write a single character in AL to the console without; mangling any registers; handle video pages correctly.;writechr: call write_serial ; write to serial port if needed pushfd test byte [cs:DisplayCon],01h jz .nothing pushad mov ah,0Eh mov bl,07h ; attribute mov bh,[cs:BIOS_page] ; current page int 10h popad.nothing: popfd ret;;; kaboom2: once everything is loaded, replace the part of kaboom; starting with "kaboom.patch" with this partkaboom2: mov si,err_bootfailed call cwritestr call getchar call vgaclearmode int 19h ; And try once more to boot....norge: jmp short .norge ; If int 19h returned; this is the end;; linsector: Convert a linear sector index in a file to a linear sector number; EAX -> linear sector number; DS:SI -> open_file_t;; Returns next sector number in EAX; CF on EOF (not an error!);linsector: push gs push ebx push esi push edi push ecx push edx push ebp push eax ; Save sector index mov cl,[ClustShift] shr eax,cl ; Convert to block number push eax mov eax,[si+file_in_sec] mov bx,si call getcachesector ; Get inode add si,[bx+file_in_off] ; Get *our* inode pop eax lea ebx,[i_block+4*eax] cmp eax,EXT2_NDIR_BLOCKS jb .direct mov ebx,i_block+4*EXT2_IND_BLOCK sub eax,EXT2_NDIR_BLOCKS mov ebp,[PtrsPerBlock1] cmp eax,ebp jb .ind1 mov ebx,i_block+4*EXT2_DIND_BLOCK sub eax,ebp mov ebp,[PtrsPerBlock2] cmp eax,ebp jb .ind2 mov ebx,i_block+4*EXT2_TIND_BLOCK sub eax,ebp.ind3: ; Triple indirect; eax contains the block no ; with respect to the start of the tind area; ; ebx contains the pointer to the tind block. xor edx,edx div dword [PtrsPerBlock2] ; EAX = which dind block, EDX = pointer within dind block push ax shr eax,SECTOR_SHIFT-2 mov ebp,[gs:si+bx] shl ebp,cl add eax,ebp call getcachesector pop bx and bx,(SECTOR_SIZE >> 2)-1 shl bx,2 mov eax,edx ; The ind2 code wants the remainder....ind2: ; Double indirect; eax contains the block no ; with respect to the start of the dind area; ; ebx contains the pointer to the dind block. xor edx,edx div dword [PtrsPerBlock1] ; EAX = which ind block, EDX = pointer within ind block push ax shr eax,SECTOR_SHIFT-2 mov ebp,[gs:si+bx] shl ebp,cl add eax,ebp call getcachesector pop bx and bx,(SECTOR_SIZE >> 2)-1 shl bx,2 mov eax,edx ; The int1 code wants the remainder....ind1: ; Single indirect; eax contains the block no ; with respect to the start of the ind area; ; ebx contains the pointer to the ind block. push ax shr eax,SECTOR_SHIFT-2 mov ebp,[gs:si+bx] shl ebp,cl add eax,ebp call getcachesector pop bx and bx,(SECTOR_SIZE >> 2)-1 shl bx,2.direct: mov ebx,[gs:bx+si] ; Get the pointer pop eax ; Get the sector index again shl ebx,cl ; Convert block number to sector and eax,[ClustMask] ; Add offset within block add eax,ebx pop ebp pop edx pop ecx pop edi pop esi pop ebx pop gs ret;; getfssec: Get multiple sectors from a file;; Same as above, except SI is a pointer to a open_file_t;; ES:BX -> Buffer; DS:SI -> Pointer to open_file_t; CX -> Sector count (0FFFFh = until end of file); Must not exceed the ES segment; Returns CF=1 on EOF (not necessarily error); All arguments are advanced to reflect data read.;getfssec: push ebp push eax push edx push edi movzx ecx,cx cmp ecx,[si] ; Number of sectors left jbe .lenok mov cx,[si].lenok:.getfragment: mov eax,[si+file_sector] ; Current start index mov edi,eax call linsector push eax ; Fragment start sector mov edx,eax xor ebp,ebp ; Fragment sector count.getseccnt: inc bp dec cx jz .do_read xor eax,eax mov ax,es shl ax,4 add ax,bx ; Now DI = how far into 64K block we are not ax ; Bytes left in 64K block inc eax shr eax,SECTOR_SHIFT ; Sectors left in 64K block cmp bp,ax jnb .do_read ; Unless there is at least 1 more sector room... inc edi ; Sector index inc edx ; Linearly next sector mov eax,edi call linsector ; jc .do_read cmp edx,eax je .getseccnt.do_read: pop eax ; Linear start sector pushad call getlinsec_ext popad push bp shl bp,9 add bx,bp ; Adjust buffer pointer pop bp add [si+file_sector],ebp ; Next sector index sub [si],ebp ; Sectors consumed jcxz .done jnz .getfragment ; Fall through.done: cmp dword [si],1 ; Did we run out of file? ; CF set if [SI] < 1, i.e. == 0 pop edi pop edx pop eax pop ebp ret; -----------------------------------------------------------------------------; Common modules; -----------------------------------------------------------------------------%include "getc.inc" ; getc et al%include "conio.inc" ; Console I/O%include "writestr.inc" ; String output%include "parseconfig.inc" ; High-level config file handling%include "parsecmd.inc" ; Low-level config file handling%include "bcopy32.inc" ; 32-bit bcopy%include "loadhigh.inc" ; Load a file into high memory%include "font.inc" ; VGA font stuff%include "graphics.inc" ; VGA graphics%include "highmem.inc" ; High memory sizing%include "strcpy.inc" ; strcpy()%include "strecpy.inc" ; strcpy with end pointer check%include "cache.inc"; -----------------------------------------------------------------------------; Begin data section; ----------------------------------------------------------------------------- section .datacopyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' db CR, LF, 0boot_prompt db 'boot: ', 0wipe_char db BS, ' ', BS, 0err_notfound db 'Could not find kernel image: ',0err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0err_noram db 'It appears your computer has less than ' asciidec dosram_k db 'K of low ("DOS")' db CR, LF db 'RAM. Linux needs at least this amount to boot. If you get' db CR, LF db 'this message in error, hold down the Ctrl key while' db CR, LF db 'booting, and I will take your word for it.', CR, LF, 0err_badcfg db 'Unknown keyword in extlinux.conf.', CR, LF, 0err_noparm db 'Missing parameter in extlinux.conf.', CR, LF, 0err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' db CR, LF, 0err_notdos db ': attempted DOS system call', CR, LF, 0err_comlarge db 'COMBOOT image too large.', CR, LF, 0err_bssimage db 'BSS images not supported.', CR, LF, 0err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' db 'a key to continue.', CR, LF, 0ready_msg db 'Ready.', CR, LF, 0crlfloading_msg db CR, LFloading_msg db 'Loading ', 0dotdot_msg db '.'dot_msg db '.', 0aborted_msg db ' aborted.' ; Fall through to crlf_msg!crlf_msg db CR, LFnull_msg db 0crff_msg db CR, FF, 0ConfigName db 'extlinux.conf',0 ; Unmangled form;; Command line options we'd like to take a look at;; mem= and vga= are handled as normal 32-bit integer valuesinitrd_cmd db 'initrd='initrd_cmd_len equ 7;; Config file keyword table;%include "keywords.inc";; Extensions to search for (in *forward* order).; align 4, db 0exten_table: db '.cbt' ; COMBOOT (specific) db '.img' ; Disk image db '.bs', 0 ; Boot sector db '.com' ; COMBOOT (same as DOS) db '.c32' ; COM32exten_table_end: dd 0, 0 ; Need 8 null bytes here;; Misc initialized (data) variables;%ifdef debug ; This code for debugging onlydebug_magic dw 0D00Dh ; Debug code sentinel%endif alignb 4, db 0BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbufBufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?BufSafeBytes dw trackbufsize ; = how many bytes?EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes%ifndef DEPEND%if ( trackbufsize % SECTOR_SIZE ) != 0%error trackbufsize must be a multiple of SECTOR_SIZE%endif%endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -