📄 ldlinux.asm
字号:
div bx ; Now we have the size of the root dir mov [RootDirSize],ax mov [DirScanCtr],ax add bx,trackbuf-31 mov [EndofDirSec],bx ; End of a single directory sector add [DataArea1],ax adc word [DataArea2],byte 0 pop dx ; Reload root directory starting point pop ax;; Now the fun begins. We have to search the root directory for; LDLINUX.SYS and load the first sector, so we have a little more; space to have fun with. Then we can go chasing through the FAT.; Joy!!;sd_nextsec: push ax push dx mov bx,trackbuf push bx call getonesec pop sisd_nextentry: cmp byte [si],0 ; Directory high water mark je kaboom mov di,ldlinux_sys mov cx,11 push si repe cmpsb pop si je found_it add si,byte 32 ; Distance to next cmp si,[EndofDirSec] jb sd_nextentry pop dx pop ax add ax,byte 1 adc dx,byte 0 dec word [DirScanCtr] jnz sd_nextsec;; kaboom: write a message and bail out.;kaboom: mov si,bailmsg call writestr ; Returns with AL = 0 cbw ; Sets AH = 0 (shorter than XOR) int 16h ; Wait for keypress mov sp,StackBuf-2*3 ; Reset stack pop si ; BIOS floppy block address cli pop word [si] ; Restore location pop word [si+2] sti int 19h ; And try once more to boot...norge: jmp short norge ; If int 19h returned; this is the end;; found_it: now we compute the location of the first sector, then; load it and JUMP (since we're almost out of space);found_it: ; Note: we actually leave two words on the stack here ; (who cares?) mov al,[bsSecPerClust] xor ah,ah mov bp,ax ; Load an entire cluster mov bx,[si+26] ; First cluster push bx ; Remember which cluster it was dec bx ; First cluster is cluster 2 dec bx mul bx add ax,[DataArea1] adc dx,[DataArea2] mov bx,ldlinux_magic push bx call getlinsec mov si,bs_magic pop di mov cx,magic_len repe cmpsb ; Make sure that the bootsector jne kaboom ; matches LDLINUX.SYS jmp ldlinux_ent;; writestr: write a null-terminated string to the console;writestr:wstr_1: lodsb and al,al jz return mov ah,0Eh ; Write to screen as TTY mov bx,0007h ; White on black, current page int 10h jmp short wstr_1;; disk_error: decrement the retry count and bail if zero;disk_error: dec si ; SI holds the disk retry counter jz kaboom xchg ax,bx ; Shorter than MOV pop bx pop cx pop dx jmp short disk_try_again;; getonesec: like getlinsec, but pre-sets the count to 1;getonesec: mov bp,1 ; Fall through to getlinsec;; getlinsec: load a sequence of BP floppy sector given by the linear sector; number in DX:AX into the buffer at ES:BX. We try to optimize; by loading up to a whole track at a time, but the user; is responsible for not crossing a 64K boundary.; (Yes, BP is weird for a count, but it was available...);; On return, BX points to the first byte after the transferred; block.;getlinsec: mov si,[bsSecPerTrack] div si ; Convert linear to sector/track mov cx,dx ; Save sector xor dx,dx ; 32-bit track number div word [bsHeads] ; Convert track to head/cyl ; ; Now we have AX = cyl, DX = head, CX = sector (0-based) ; for the very first sector, SI = bsSecPerTrack ;gls_nexttrack: push si push bp sub si,cx ; Sectors left on track cmp bp,si jna gls_lasttrack mov bp,si ; No more than a trackful, please!gls_lasttrack: push ax ; Cylinder # push dx ; Head # push bp ; Number of sectors we're transferring push cx mov cl,6 ; Because IBM was STOOPID shl ah,cl ; and thought 8 bits were enough ; then thought 10 bits were enough... pop cx ; Sector # inc cx ; Sector numbers are 1-based or cl,ah mov ch,al mov dh,dl mov dl,[bsDriveNumber] xchg ax,bp ; Sector to transfer count ; (xchg shorter than mov) mov ah,02h ; Read it!;; Do the disk transfer... save the registers in case we fail :(; mov si,retry_count ; # of times to retry a disk accessdisk_try_again: push dx push cx push bx push ax push si int 13h pop si pop bx jc disk_error;; It seems the following test fails on some machines (buggy BIOS?);; cmp al,bl ; Check that we got what we asked for; jne disk_error;; Disk access successful; pop bx ; Buffer location pop si ; Not needed anymore pop si ; Neither is this pop si ; Sector transferred count mov ax,si ; Reduce sector left count mul word [bsBytesPerSec] ; Figure out how much to advance ptr add bx,ax ; Update buffer location pop dx ; Head # pop ax ; Cyl # inc dx ; Next track on cyl cmp dx,[bsHeads] ; Was this the last one? jb gls_nonewcyl inc ax ; If so, new cylinder xor dx,dx ; First head on new cylindergls_nonewcyl: pop bp ; Sectors left to transfer xor cx,cx ; First sector on new track sub bp,si ; Reduce with # of sectors just read pop si ja gls_nexttrackreturn: retbailmsg db 'Boot failed: change disks and press any key', 0Dh, 0Ah, 0bs_checkpt equ $ ; Must be <= 1E5h zb 1E3h-($-$$)bs_magic equ $ ; The following 32 bytes should ; match ldlinux_magicldlinux_sys db 'LDLINUX SYS' ; Looks like this in the root dir db ' 'bs_version db version_str db ' 'bs_date db datemagic_len equ $-bs_magicbootsignature dw 0AA55h;; ===========================================================================; End of boot sector; ===========================================================================; Start of LDLINUX.SYS; ===========================================================================;; This "magic number" works well with the "type" command... :-);ldlinux_magic db 'LDLINUX'missing_dot db ' ' db 'SYS ', version_str, ' ', datemagic_eof db 0Dh, 0Ah, 01Ah zb 220h-($-$$)ldlinux_ent:;; The boot sector left the cluster number of this first LDLINUX.SYS; sector on the stack. We'll need it later, so we should pop it off; pop word [RunLinClust];; Tell the user we got this far; mov si,crlf call writestr mov byte [missing_dot],'.' mov byte [magic_eof],0 mov si,ldlinux_magic call writestr;; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS.; We can really only rely on a single sector having been loaded. Hence; we should load the FAT into RAM and start chasing pointers...; mov bx,FAT ; Where it goes in memory mov ax,[bsHidden1] ; Hidden sectors mov dx,[bsHidden2] add ax,[bsResSectors] ; plus reserved sectors = FAT adc dx,byte 0 mov bp,[bsFATsecs] ; Sectors/FAT call getlinsec ; Load it in...;; Fine, now we have the FAT in memory. How big is a cluster, really?; Also figure out how many clusters will fit in an 8K buffer, and how; many sectors and bytes that is; mov al,[bsSecPerClust] ; We do this in the boot xor ah,ah ; sector, too, but there mov [SecPerClust],ax ; wasn't space to save it mul word [bsBytesPerSec] mov [ClustSize],ax ; Bytes/cluster mov bx,ax mov ax,trackbufsize xor dx,dx div bx mov [BufSafe],ax ; # of cluster in trackbuf mul word [SecPerClust] mov [BufSafeSec],ax mul word [bsBytesPerSec] mov [BufSafeBytes],ax add ax,getcbuf ; getcbuf is same size as mov [EndOfGetCBuf],ax ; trackbuf, for simplicity;; Now we read the rest of LDLINUX.SYS. Don't bother loading the first; cluster again, though.; mov bx,ldlinux_magic add bx,[ClustSize] mov si,[RunLinClust] call nextcluster xor dx,dx mov ax,ldlinux_len-1 ; To be on the safe side add ax,[ClustSize] div word [ClustSize] ; the number of clusters dec ax ; We've already read one jz all_read_jmp mov cx,ax call getfssec;; All loaded up;all_read_jmp: mov si,copyright_str call writestr jmp all_read;; -----------------------------------------------------------------------------; Subroutines that have to be in the first sector; -----------------------------------------------------------------------------;; getfssec: Get multiple clusters from a file, given the starting cluster.;; This routine makes sure the subtransfers do not cross a 64K boundary,; and will correct the situation if it does, UNLESS *sectors* cross; 64K boundaries.;; ES:BX -> Buffer; SI -> Starting cluster number (2-based); CX -> Cluster count (0FFFFh = until end of file); ; 386 checkgetfssec:getfragment: xor bp,bp ; Fragment sector count mov ax,si ; Get sector address dec ax ; Convert to 0-based dec ax mul word [SecPerClust] add ax,[DataArea1] adc dx,[DataArea2]getseccnt: ; See if we can read > 1 clust add bp,[SecPerClust] dec cx ; Reduce clusters left to find mov di,si ; Predict next cluster inc di call nextcluster jc gfs_eof ; At EOF? jcxz endfragment ; Or was it the last we wanted? cmp si,di ; Is file continuous? jz getseccnt ; Yes, we can getendfragment: clc ; Not at EOFgfs_eof: pushf ; Remember EOF or not push si push cxgfs_getchunk: push ax push dx mov ax,es ; Check for 64K boundaries. shl ax,1 ; This really belongs in shl ax,1 ; getlinsec, but it would shl ax,1 ; make it not fit in the boot shl ax,1 ; sector. add ax,bx xor dx,dx neg ax jnz gfs_partseg inc dx ; Full 64K segmentgfs_partseg: div word [bsBytesPerSec] ; How many sectors fit? mov si,bp sub si,ax ; Compute remaining sectors jbe gfs_lastchunk mov bp,ax pop dx pop ax push si ; Save remaining sector count push ax ; Save position push dx push bp ; Save sectors to transfer call getlinsec pop bp pop dx pop ax add ax,bp ; Advance sector pointer adc dx,byte 0 pop bp ; Load remaining sector counter jmp short gfs_getchunkgfs_lastchunk: pop dx pop ax call getlinsec pop cx pop si popf jcxz gfs_return ; If we hit the count limit jnc getfragment ; If we didn't hit EOFgfs_return: ret;; nextcluster: Advance a cluster pointer in SI to the next cluster; pointed at in the FAT tables (note: FAT12 assumed); Sets CF on return if end of file.;nextcluster:nextcluster_fat12: push ax mov ax,si ; Multiply by 3/2 shr ax,1 pushf ; CF now set if odd add si,ax mov si,[FAT+si] popf jnc nc_even shr si,1 ; Needed for odd only shr si,1 shr si,1 shr si,1nc_even: and si,0FFFh cmp si,0FF0h ; Clears CF if at end of file cmc ; But we want it SET... pop axnc_return: retnextcluster_fat16: push ax push es mov ax,(fat_seg >> 12) shl si,1 adc ax,byte 0 mov es,ax mov si,[es:si] cmp si,0FFF0h cmc pop es pop ax ret;; Debug routine;%ifdef debugsafedumpregs: cmp word [Debug_Magic],0D00Dh jnz nc_return jmp dumpregs%endif;; Data that has to be in the first sector;copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'crlf db 0Dh, 0Ah, 0rl_checkpt equ $ ; Must be <= 400h; ----------------------------------------------------------------------------; End of code and data that have to be in the first sector; ----------------------------------------------------------------------------all_read:;; Check that no moron is trying to boot Linux on a 286 or so. According; to Intel, the way to check is to see if the high 4 bits of the FLAGS; register are either all stuck at 1 (8086/8088) or all stuck at 0; (286 in real mode), if not it is a 386 or higher. They didn't
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -