📄 ldlinux.asm
字号:
; -*- fundamental -*- (asm-mode sucks); $Id: ldlinux.asm,v 1.147 2004/06/13 20:50:44 hpa Exp $; ****************************************************************************;; ldlinux.asm;; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This; functionality is good to have for installation floppies, where it may; be hard to find a functional Linux system to run LILO off.;; This program allows manipulation of the disk to take place entirely; from MS-LOSS, and can be especially useful in conjunction with the; umsdos filesystem.;; This file is loaded in stages; first the boot sector at offset 7C00h,; then the first sector (cluster, really, but we can only assume 1 sector); of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h.;; Copyright (C) 1994-2004 H. Peter Anvin;; This program is free software; you can redistribute it and/or modify; it under the terms of the GNU General Public License as published by; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,; USA; either version 2 of the License, or (at your option) any later; version; incorporated herein by reference.; ; ****************************************************************************%ifndef IS_MDSLINUX%define IS_SYSLINUX 1%endif%include "macros.inc"%include "config.inc"%include "kernel.inc"%include "bios.inc"%include "tracers.inc";; Some semi-configurable constants... change on your own risk.;my_id equ syslinux_idFILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null)FILENAME_MAX equ 11 ; Max mangled filename sizeNULLFILE equ ' ' ; First char space == null filenameretry_count equ 6 ; How patient are we with the disk?%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top;; This is what we need to do when idle;%macro RESET_IDLE 0 ; Nothing%endmacro%macro DO_IDLE 0 ; Nothing%endmacro;; The following structure is used for "virtual kernels"; i.e. LILO-style; option labels. The options we permit here are `kernel' and `append; Since there is no room in the bottom 64K for all of these, we; stick them at vk_seg:0000 and copy them down before we need them.;; Note: this structure can be added to, but it must ;%define vk_power 7 ; log2(max number of vkernels)%define max_vk (1 << vk_power) ; Maximum number of vkernels%define vk_shift (16-vk_power) ; Number of bits to shift%define vk_size (1 << vk_shift) ; Size of a vkernel buffer struc vkernelvk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**vk_rname: resb FILENAME_MAX ; Real namevk_appendlen: resw 1 alignb 4vk_append: resb max_cmd_len+1 ; Command line alignb 4vk_end: equ $ ; Should be <= vk_size endstruc%ifndef DEPEND%if (vk_end > vk_size) || (vk_size*max_vk > 65536)%error "Too many vkernels defined, reduce vk_power"%endif%endif;; Segment assignments in the bottom 640K; Stick to the low 512K in case we're using something like M-systems flash; which load a driver into low RAM (evil!!);; 0000h - main code/data segment (and BIOS segment);real_mode_seg equ 5000hfat_seg equ 3000h ; 128K area for FAT (2x64K)vk_seg equ 2000h ; Virtual kernelsxfer_buf_seg equ 1000h ; Bounce buffer for I/O to high memcomboot_seg equ real_mode_seg ; COMBOOT image loading zone; ---------------------------------------------------------------------------; BEGIN CODE; ---------------------------------------------------------------------------;; Memory below this point is reserved for the BIOS and the MBR; absolute 1000htrackbuf equ $ ; Track buffer goes heretrackbufsize equ 16384 ; Safe size of track buffer; trackbuf ends at 5000h;; Constants for the xfer_buf_seg;; The xfer_buf_seg is also used to store message file buffers. We; need two trackbuffers (text and graphics), plus a work buffer; for the graphics decompressor.;xbs_textbuf equ 0 ; Also hard-coded, do not changexbs_vgabuf equ trackbufsizexbs_vgatmpbuf equ 2*trackbufsize absolute 5000h ; Here we keep our BSS stuffVKernelBuf: resb vk_size ; "Current" vkernel alignb 4AppendBuf resb max_cmd_len+1 ; append=Ontimeout resb max_cmd_len+1 ; ontimeoutOnerror resb max_cmd_len+1 ; onerrorKbdMap resb 256 ; Keyboard mapFKeyName resb 10*16 ; File names for F-key helpNumBuf resb 15 ; Buffer to load numberNumBufEnd resb 1 ; Last byte in NumBuf alignb 8 ; Expanded superblockSuperInfo equ $ resq 16 ; The first 16 bytes expanded 8 times ; ; These need to follow SuperInfo ;RootDir resd 1 ; Location of root directoryDataArea resd 1 ; Location of data areaRootDirSize resw 1 ; Root dir size in sectorsDirScanCtr resw 1 ; Used while searching directoryEndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 alignb 4E820Buf resd 5 ; INT 15:E820 data bufferE820Mem resd 1 ; Memory detected by E820E820Max resd 1 ; Is E820 memory capped?HiLoadAddr resd 1 ; Address pointer for high load loopHighMemSize resd 1 ; End of memory pointer (bytes)RamdiskMax resd 1 ; Highest address for a ramdiskKernelSize resd 1 ; Size of kernel (bytes)SavedSSSP resd 1 ; Our SS:SP while running a COMBOOT imagePMESP resd 1 ; Protected-mode ESPClustPerMoby resd 1 ; Clusters per 64KClustSize resd 1 ; Bytes/clusterKernelName resb 12 ; Mangled name for kernel ; (note the spare byte after!)OrigKernelExt resd 1 ; Original kernel extensionFBytes equ $ ; Used by open/getcFBytes1 resw 1FBytes2 resw 1DirBlocksLeft resw 1 ; DittoRunLinClust resw 1 ; Cluster # for LDLINUX.SYSBufSafe resw 1 ; Clusters we can load into trackbufBufSafeSec resw 1 ; = how many sectors?BufSafeBytes resw 1 ; = how many bytes?EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytesKernelClust resw 1 ; Kernel size in clustersFClust resw 1 ; Number of clusters in open/getc fileFNextClust resw 1 ; Pointer to next cluster in d:oFPtr resw 1 ; Pointer to next char in bufferCmdOptPtr resw 1 ; Pointer to first option on cmd lineKernelCNameLen resw 1 ; Length of unmangled kernel nameInitRDCNameLen resw 1 ; Length of unmangled initrd nameNextCharJump resw 1 ; Routine to interpret next print charSetupSecs resw 1 ; Number of setup sectorsA20Test resw 1 ; Counter for testing status of A20A20Type resw 1 ; A20 typeCmdLineLen resw 1 ; Length of command line including nullGraphXSize resw 1 ; Width of splash screen fileVGAPos resw 1 ; Pointer into VGA memoryVGACluster resw 1 ; Cluster pointer for VGA image fileVGAFilePtr resw 1 ; Pointer into VGAFileBufCom32SysSP resw 1 ; SP saved during COM32 syscallCursorDX equ $CursorCol resb 1 ; Cursor column for message fileCursorRow resb 1 ; Cursor row for message fileScreenSize equ $VidCols resb 1 ; Columns on screen-1VidRows resb 1 ; Rows on screen-1BaudDivisor resw 1 ; Baud rate divisorFlowControl equ $FlowOutput resb 1 ; Outputs to assert for serial flowFlowInput resb 1 ; Input bits for serial flowFlowIgnore resb 1 ; Ignore input unless these bits setTextAttribute resb 1 ; Text attribute for message fileRetryCount resb 1 ; Used for disk access retriesKbdFlags resb 1 ; Check for keyboard escapesLoadFlags resb 1 ; Loadflags from kernelA20Tries resb 1 ; Times until giving up on A20FuncFlag resb 1 ; Escape sequences received from keyboardDisplayMask resb 1 ; Display modes maskCopySuper resb 1 ; Distinguish .bs versus .bssMNameBuf resb 11 ; Generic mangled file name bufferInitRD resb 11 ; initrd= mangled nameKernelCName resb 13 ; Unmangled kernel nameInitRDCName resb 13 ; Unmangled initrd nameTextColorReg resb 17 ; VGA color registers for text modeVGAFileBuf resb 13 ; Unmangled VGA image nameVGAFileBufEnd equ $VGAFileMBuf resb 11 ; Mangled VGA image name alignb 4 ; For the good of REP MOVSDcommand_line resb max_cmd_len+2 ; Command line bufferdefault_cmd resb max_cmd_len+1 ; "default" command linekern_cmd_len equ $-command_line section .text org 7C00h;; Some of the things that have to be saved very early are saved; "close" to the initial stack pointer offset, in order to; reduce the code size...;StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)PartInfo equ StackBuf ; Saved partition table entryFloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack;; Primary entry point. Tempting as though it may be, we can't put the; initial "cli" here; the jmp opcode in the first byte is part of the; "magic number" (using the term very loosely) for the DOS superblock.;bootsec equ $ jmp short start ; 2 bytes nop ; 1 byte;; "Superblock" follows -- it's in the boot sector, so it's already; loaded and ready for us;bsOemName db 'SYSLINUX' ; The SYS command sets this, so...;; These are the fields we actually care about. We end up expanding them; all to dword size early in the code, so generate labels for both; the expanded and unexpanded versions.;;%macro superb 1bx %+ %1 equ SuperInfo+($-superblock)*8+4bs %+ %1 equ $ zb 1%endmacro%macro superw 1bx %+ %1 equ SuperInfo+($-superblock)*8bs %+ %1 equ $ zw 1%endmacro%macro superd 1bx %+ %1 equ $ ; no expansion for dwordsbs %+ %1 equ $ zd 1%endmacrosuperblock equ $ superw BytesPerSec superb SecPerClust superw ResSectors superb FATs superw RootDirEnts superw Sectors superb Media superw FATsecs superw SecPerTrack superw Headssuperinfo_size equ ($-superblock)-1 ; How much to expand superd Hidden superd HugeSectors superb DriveNumber superb Reserved1 superb BootSignature ; 29h if the following fields exist superd VolumeIDbsVolumeLabel zb 11bsFileSysType zb 8 ; Must be FAT12 or FAT16 for this versionsuperblock_len equ $-superblockSecPerClust equ bxSecPerClust;; Note we don't check the constraints above now; we did that at install; time (we hope!);;floppy_table equ $ ; No sense in wasting memory, overwrite startstart: cli ; No interrupts yet, please cld ; Copy upwards;; Set up the stack; xor ax,ax mov ss,ax mov sp,StackBuf ; Just below BSS mov es,ax;; DS:SI may contain a partition table entry. Preserve it for us.; mov cx,8 ; Save partition info mov di,sp rep movsw mov ds,ax ; Now we can initialize DS... mov [di+bsDriveNumber-FloppyTable],dl;; Now sautee the BIOS floppy info block to that it will support decent-; size transfers; the floppy block is 11 bytes and is stored in the; INT 1Eh vector (brilliant waste of resources, eh?);; Of course, if BIOSes had been properly programmed, we wouldn't have; had to waste precious space with this code.; mov bx,fdctab lfs si,[bx] ; FS:SI -> original fdctab push fs ; Save on stack in case we need to bail push si ; Save the old fdctab even if hard disk so the stack layout ; is the same. The instructions above do not change the flags and dl,dl ; If floppy disk (00-7F), assume no ; partition table js harddiskfloppy: mov cl,6 ; 12 bytes (CX == 0) ; es:di -> FloppyTable already ; This should be safe to do now, interrupts are off... mov [bx],di ; FloppyTable mov [bx+2],ax ; Segment 0 fs rep movsw ; Faster to move words mov cl,[bsSecPerTrack] ; Patch the sector count mov [di-8],cl ; AX == 0 here int 13h ; Some BIOSes need this jmp short not_harddisk;; The drive number and possibly partition information was passed to us; by the BIOS or previous boot loader (MBR). Current "best practice" is to; trust that rather than what the superblock contains.;; Would it be better to zero out bsHidden if we don't have a partition table?;; Note: di points to beyond the end of PartInfo;harddisk: test byte [di-16],7Fh ; Sanity check: "active flag" should jnz no_partition ; be 00 or 80 mov eax,[di-8] ; Partition offset (dword) mov [bsHidden],eaxno_partition:;; Get disk drive parameters (don't trust the superblock.) Don't do this for; floppy drives -- INT 13:08 on floppy drives will (may?) return info about; what the *drive* supports, not about the *media*. Fortunately floppy disks; tend to have a fixed, well-defined geometry which is stored in the superblock.; ; DL == drive # still mov ah,08h int 13h jc no_driveparm and ah,ah jnz no_driveparm shr dx,8 inc dx ; Contains # of heads - 1 mov [bsHeads],dx and cx,3fh mov [bsSecPerTrack],cxno_driveparm:not_harddisk:;; Ready to enable interrupts, captain; sti;; Insane hack to expand the superblock to dwords;expand_super: xor eax,eax mov es,ax ; INT 13:08 destroys ES mov si,superblock mov di,SuperInfo mov cl,superinfo_size ; CH == 0.loop: lodsw dec si stosd ; Store expanded word xor ah,ah stosd ; Store expanded byte loop .loop;; Now we have to do some arithmetric to figure out where things are located.; If Micro$oft had had brains they would already have done this for us,; and stored it in the superblock at format time, but here we go,; wasting precious boot sector space again...;%define Z di-superinfo_size*8-SuperInfodebugentrypt: mov ax,[bxFATs] ; Number of FATs (eax<31:16> == 0) mov edx,[Z+bxFATsecs] ; Sectors/FAT mul edx ; Get the size of the FAT area ; edx <- 0 add eax,[bxHidden] ; Add hidden sectors add eax,[Z+bxResSectors] ; And reserved sectors mov [RootDir],eax ; Location of root directory mov [DataArea],eax ; First data sector push eax mov eax,[Z+bxRootDirEnts] shl ax,5 ; Size of a directory entry mov bx,[Z+bxBytesPerSec] add ax,bx ; Round up, not down dec ax div bx ; Now we have the size of the root dir mov [RootDirSize],ax mov [DirScanCtr],ax add bx,trackbuf-31 mov [Z+EndofDirSec],bx ; End of a single directory sector add [Z+DataArea],eax pop eax ; Reload root directory starting point;; 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 eax mov bx,trackbuf push bx call getonesec pop sisd_nextentry: mov cx,11 cmp [si],ch ; Directory high water mark je kaboom; This no longer fits... since we'd be dead anyway if there; was a nonfile named LDLINUX.SYS on the disk, it shouldn't; matter...; test byte [si+11],18h ; Must be a file; jnz sd_not_file mov di,ldlinux_name push si repe cmpsb pop si je found_itsd_not_file: add si,byte 32 ; Distance to next cmp si,[EndofDirSec] jb sd_nextentry pop eax inc eax dec word [DirScanCtr] jnz sd_nextsec;; kaboom: write a message and bail out.;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: mov si,bailmsg call writestr ; Returns with AL = 0 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;; 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 eax,[bxSecPerClust] mov bp,ax ; Load an entire cluster movzx ebx,word [si+26] ; First cluster mov [RunLinClust],bx ; Save for later use dec bx ; First cluster is "cluster 2" dec bx mul ebx add eax,[DataArea] mov bx,ldlinux_sys
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -