📄 extlinux.asm
字号:
; Truncate BP to MaxTransfer;maxtrans: cmp bp,[MaxTransfer] jna .ok mov bp,[MaxTransfer].ok: ret;; Error message on failure;bailmsg: db 'Boot error', 0Dh, 0Ah, 0 ; This fails if the boot sector overflows zb 1F8h-($-$$)FirstSector dd 0xDEADBEEF ; Location of sector 1MaxTransfer dw 0x007F ; Max transfer sizebootsignature dw 0AA55h;; ===========================================================================; End of boot sector; ===========================================================================; Start of LDLINUX.SYS; ===========================================================================ldlinux_sys:syslinux_banner db 0Dh, 0Ah db 'EXTLINUX ' db version_str, ' ', date, ' ', 0 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS align 8, db 0ldlinux_magic dd LDLINUX_MAGIC dd LDLINUX_MAGIC^HEXDATE;; This area is patched by the installer. It is found by looking for; LDLINUX_MAGIC, plus 8 bytes.;patch_area:LDLDwords dw 0 ; Total dwords starting at ldlinux_sysLDLSectors dw 0 ; Number of sectors - (bootsec+this sec)CheckSum dd 0 ; Checksum starting at ldlinux_sys ; value = LDLINUX_MAGIC - [sum of dwords]CurrentDir dd 2 ; "Current" directory inode number; Space for up to 64 sectors, the theoretical maximumSectorPtrs times 64 dd 0ldlinux_ent:; ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000; instead of 0000:7C00 and the like. We don't want to add anything; more to the boot sector, so it is written to not assume a fixed; value in CS, but we don't want to deal with that anymore from now; on.; jmp 0:.next.next:;; Tell the user we got this far; mov si,syslinux_banner call writestr;; Tell the user if we're using EBIOS or CBIOS;print_bios: mov si,cbios_name cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2)) jne .cbios mov si,ebios_name.cbios: mov [BIOSName],si call writestr section .bss%define HAVE_BIOSNAME 1BIOSName resw 1 section .text;; Now we read the rest of LDLINUX.SYS. Don't bother loading the first; sector again, though.;load_rest: mov si,SectorPtrs mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading mov cx,[LDLSectors].get_chunk: jcxz .done xor bp,bp lodsd ; First sector of this chunk mov edx,eax.make_chunk: inc bp dec cx jz .chunk_ready inc edx ; Next linear sector cmp [si],edx ; Does it match jnz .chunk_ready ; If not, this is it add si,4 ; If so, add sector to chunk jmp short .make_chunk.chunk_ready: call getlinsecsr shl bp,SECTOR_SHIFT add bx,bp jmp .get_chunk.done:;; All loaded up, verify that we got what we needed.; Note: the checksum field is embedded in the checksum region, so; by the time we get to the end it should all cancel out.;verify_checksum: mov si,ldlinux_sys mov cx,[LDLDwords] mov edx,-LDLINUX_MAGIC.checksum: lodsd add edx,eax loop .checksum and edx,edx ; Should be zero jz all_read ; We're cool, go for it!;; Uh-oh, something went bad...; mov si,checksumerr_msg call writestr jmp kaboom;; -----------------------------------------------------------------------------; Subroutines that have to be in the first sector; -----------------------------------------------------------------------------;;; writestr: write a null-terminated string to the console; This assumes we're on page 0. This is only used for early; messages, so it should be OK.;writestr:.loop: lodsb and al,al jz .return mov ah,0Eh ; Write to screen as TTY mov bx,0007h ; Attribute int 10h jmp short .loop.return: ret; getlinsecsr: save registers, call getlinsec, restore registers;getlinsecsr: pushad call getlinsec popad ret;; Checksum error message;checksumerr_msg db ' Load error - ', 0 ; Boot failed appended;; BIOS type string;cbios_name db 'CBIOS', 0ebios_name db 'EBIOS', 0;; Debug routine;%ifdef debugsafedumpregs: cmp word [Debug_Magic],0D00Dh jnz nc_return jmp dumpregs%endifrl_checkpt equ $ ; Must be <= 8000hrl_checkpt_off equ ($-$$)%ifndef DEPEND%if rl_checkpt_off > 400h%error "Sector 1 overflow"%endif%endif; ----------------------------------------------------------------------------; End of code and data that have to be in the first sector; ----------------------------------------------------------------------------all_read:;; Let the user (and programmer!) know we got this far. This used to be; in Sector 1, but makes a lot more sense here.; mov si,copyright_str call writestr;; Insane hack to expand the DOS superblock to dwords;expand_super: xor eax,eax mov si,superblock mov di,SuperInfo mov cx,superinfo_size.loop: lodsw dec si stosd ; Store expanded word xor ah,ah stosd ; Store expanded byte loop .loop;; Load the real (ext2) superblock; 1024 bytes long at offset 1024; mov bx,SuperBlock mov eax,1024 >> SECTOR_SHIFT mov bp,ax call getlinsec;; Compute some values...; xor edx,edx inc edx ; s_log_block_size = log2(blocksize) - 10 mov cl,[SuperBlock+s_log_block_size] add cl,10 mov [ClustByteShift],cl mov eax,edx shl eax,cl mov [ClustSize],eax sub cl,SECTOR_SHIFT mov [ClustShift],cl shr eax,SECTOR_SHIFT mov [SecPerClust],eax dec eax mov [ClustMask],eax add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer shl edx,cl mov [PtrsPerBlock1],edx shl edx,cl mov [PtrsPerBlock2],edx;; Common initialization code;%include "init.inc"%include "cpuinit.inc";; Initialize the metadata cache; call initcache;; Now, everything is "up and running"... patch kaboom for more; verbosity and using the full screen system; ; E9 = JMP NEAR mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8);; Now we're all set to start with our *real* business. First load the; configuration file (if any) and parse it.;; In previous versions I avoided using 32-bit registers because of a; rumour some BIOSes clobbered the upper half of 32-bit registers at; random. I figure, though, that if there are any of those still left; they probably won't be trying to install Linux on them...;; The code is still ripe with 16-bitisms, though. Not worth the hassle; to take'm out. In fact, we may want to put them back if we're going; to boot ELKS at some point.;;; Load configuration file;load_config: mov di,ConfigName call open jz no_config_file;; Now we have the config file open. Parse the config file and; run the user interface.;%include "ui.inc";; Linux kernel loading code is common.;%include "runkernel.inc";; COMBOOT-loading code;%include "comboot.inc"%include "com32.inc"%include "cmdline.inc";; Boot sector loading code;%include "bootsect.inc";; getlinsec_ext: same as getlinsec, except load any sector from the zero; block as all zeros; use to load any data derived; from an ext2 block pointer, i.e. anything *except the; superblock.*;getonesec_ext: mov bp,1getlinsec_ext: cmp eax,[SecPerClust] jae getlinsec ; Nothing fancy ; If we get here, at least part of what we want is in the ; zero block. Zero one sector at a time and loop. push eax push cx xchg di,bx xor eax,eax mov cx,SECTOR_SIZE >> 2 rep stosd xchg di,bx pop cx pop eax inc eax dec bp jnz getlinsec_ext ret;; Abort loading code;%include "abort.inc";; allocate_file: Allocate a file structure;; If successful:; ZF set; BX = file pointer; In unsuccessful:; ZF clear;allocate_file: TRACER 'a' push cx mov bx,Files mov cx,MAX_OPEN.check: cmp dword [bx], byte 0 je .found add bx,open_file_t_size ; ZF = 0 loop .check ; ZF = 0 if we fell out of the loop.found: pop cx ret;; open_inode:; Open a file indicated by an inode number in EAX;; NOTE: This file considers finding a zero-length file an; error. This is so we don't have to deal with that special; case elsewhere in the program (most loops have the test; at the end).;; If successful:; ZF clear; SI = file pointer; DX:AX = EAX = file length in bytes; ThisInode = the first 128 bytes of the inode; If unsuccessful; ZF set;; Assumes CS == DS == ES.;open_inode.allocate_failure: xor eax,eax pop bx pop di retopen_inode: push di push bx call allocate_file jnz .allocate_failure push cx push gs ; First, get the appropriate inode group and index dec eax ; There is no inode 0 xor edx,edx mov [bx+file_sector],edx div dword [SuperBlock+s_inodes_per_group] ; EAX = inode group; EDX = inode within group push edx ; Now, we need the block group descriptor. ; To get that, we first need the relevant descriptor block. shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table xor edx,edx div dword [ClustSize] ; eax = block #, edx = offset in block add eax,dword [SuperBlock+s_first_data_block] inc eax ; s_first_data_block+1 mov cl,[ClustShift] shl eax,cl push edx shr edx,SECTOR_SHIFT add eax,edx pop edx and dx,SECTOR_SIZE-1 call getcachesector ; Get the group descriptor add si,dx mov esi,[gs:si+bg_inode_table] ; Get inode table block # pop eax ; Get inode within group movzx edx, word [SuperBlock+s_inode_size] mul edx ; edx:eax = byte offset in inode table div dword [ClustSize] ; eax = block # versus inode table, edx = offset in block add eax,esi shl eax,cl ; Turn into sector push dx shr edx,SECTOR_SHIFT add eax,edx mov [bx+file_in_sec],eax pop dx and dx,SECTOR_SIZE-1 mov [bx+file_in_off],dx call getcachesector add si,dx mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2 mov di,ThisInode gs rep movsd mov ax,[ThisInode+i_mode] mov [bx+file_mode],ax mov eax,[ThisInode+i_size] push eax add eax,SECTOR_SIZE-1 shr eax,SECTOR_SHIFT mov [bx+file_left],eax pop eax mov si,bx mov edx,eax shr edx,16 ; 16-bitism, sigh and eax,eax ; ZF clear unless zero-length file pop gs pop cx pop bx pop di ret section .latebss alignb 4ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode section .text;; close:; Deallocates a file structure (pointer in SI); Assumes CS == DS.;close: mov dword [si],0 ; First dword == file_left ret;; searchdir:; Search the root directory for a pre-mangled filename in DS:DI.;; NOTE: This file considers finding a zero-length file an; error. This is so we don't have to deal with that special; case elsewhere in the program (most loops have the test; at the end).;; If successful:; ZF clear; SI = file pointer; DX:AX = EAX = file length in bytes; If unsuccessful; ZF set;; Assumes CS == DS == ES; *** IS THIS CORRECT ***?;searchdir: push bx push cx push bp mov byte [SymlinkCtr],MAX_SYMLINKS mov eax,[CurrentDir].begin_path:.leadingslash: cmp byte [di],'/' ; Absolute filename? jne .gotdir mov eax,EXT2_ROOT_INO inc di ; Skip slash jmp .leadingslash.gotdir: ; At this point, EAX contains the directory inode, ; and DS:DI contains a pathname tail..open: push eax ; Save directory inode call open_inode jz .done ; If error, done mov cx,[si+file_mode] shr cx,S_IFSHIFT ; Get file type cmp cx,T_IFDIR je .directory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -