📄 ldlinux.asm
字号:
ret.error: dec bp jnz .retry xchg ax,bp ; Sectors transferred <- 0 shr word [MaxTransfer],1 jnz .resume ; Fall through to disk_error ;; kaboom: write a message and bail out.;disk_error:kaboom: xor si,si mov ss,si mov sp,StackBuf-4 ; Reset stack mov ds,si ; Reset data segment pop dword [fdctab] ; Restore FDC table.patch: ; When we have full code, intercept here mov si,bailmsg ; Write error message, this assumes screen page 0.loop: lodsb and al,al jz .done mov ah,0Eh ; Write to screen as TTY mov bx,0007h ; Attribute int 10h jmp short .loop.done: cbw ; AH <- 0 int 16h ; Wait for keypress int 19h ; And try once more to boot....norge: jmp short .norge ; If int 19h returned; this is the end;; 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%if IS_MDSLINUX db 'MDSLINUX '%else db 'SYSLINUX '%endif 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]; 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 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;; Compute some information about this filesystem.;; First, generate the map of regionsgenfatinfo: mov edx,[bxSectors] and dx,dx jnz .have_secs mov edx,[bsHugeSectors].have_secs: mov [TotalSectors],edx add edx,eax mov [EndSector],edx mov eax,[bxResSectors] mov [FAT],eax ; Beginning of FAT mov edx,[bxFATsecs] and dx,dx jnz .have_fatsecs mov edx,[bootsec+36] ; FAT32 BPB_FATsz32.have_fatsecs: imul edx,[bxFATs] add eax,edx mov [RootDirArea],eax ; Beginning of root directory mov [RootDir],eax ; For FAT12/16 == root dir location mov edx,[bxRootDirEnts] add dx,SECTOR_SIZE/32-1 shr dx,SECTOR_SHIFT-5 mov [RootDirSize],edx add eax,edx mov [DataArea],eax ; Beginning of data area; Next, generate a cluster size shift count and mask mov eax,[bxSecPerClust] bsr cx,ax mov [ClustShift],cl push cx add cl,9 mov [ClustByteShift],cl pop cx dec ax mov [ClustMask],eax inc ax shl eax,9 mov [ClustSize],eax;; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.;getfattype: mov eax,[EndSector] sub eax,[DataArea] shr eax,cl ; cl == ClustShift mov cl,nextcluster_fat12-(nextcluster+2) cmp eax,4085 ; FAT12 limit jb .setsize mov cl,nextcluster_fat16-(nextcluster+2) cmp eax,65525 ; FAT16 limit jb .setsize ; ; FAT32, root directory is a cluster chain ; mov cl,[ClustShift] mov eax,[bootsec+44] ; Root directory cluster sub eax,2 shl eax,cl add eax,[DataArea] mov [RootDir],eax mov cl,nextcluster_fat28-(nextcluster+2).setsize: mov byte [nextcluster+1],cl;; Common initialization code;%include "cpuinit.inc"%include "init.inc";; Clear Files structures; mov di,Files mov cx,(MAX_OPEN*open_file_t_size)/4 xor eax,eax rep stosd;; 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; mov di,syslinux_cfg 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";; 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;; 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 = file length in bytes; If unsuccessful; ZF set;searchdir: push bx call allocate_file jnz .alloc_failure push cx push gs push es push ds pop es ; ES = DS mov eax,[RootDir] ; First root directory sector.scansector: call getcachesector ; GS:SI now points to this sector mov cx,SECTOR_SIZE/32 ; 32 == directory entry size.scanentry: cmp byte [gs:si],0 jz .failure ; Hit directory high water mark push cx push si push di mov cx,11 gs repe cmpsb pop di pop si pop cx jz .found add si,32 loop .scanentry call nextsector jnc .scansector ; CF is set if we're at end ; If we get here, we failed.failure: pop es pop gs pop cx.alloc_failure: pop bx xor eax,eax ; ZF <- 1 ret.found: mov eax,[gs:si+28] ; File size add eax,SECTOR_SIZE-1 shr eax,SECTOR_SHIFT jz .failure ; Zero-length file mov [bx+4],eax
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -