📄 isolinux.asm
字号:
; -*- fundamental -*- (asm-mode sucks); $Id$; ****************************************************************************;; isolinux.asm;; A program to boot Linux kernels off a CD-ROM using the El Torito; boot standard in "no emulation" mode, making the entire filesystem; available. It is based on the SYSLINUX boot loader for MS-DOS; floppies.;; Copyright (C) 1994-2005 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., 53 Temple Place Ste 330,; Boston MA 02111-1307, USA; either version 2 of the License, or; (at your option) any later version; incorporated herein by reference.;; ****************************************************************************%define IS_ISOLINUX 1%include "macros.inc"%include "config.inc"%include "kernel.inc"%include "bios.inc"%include "tracers.inc"%include "layout.inc";; Some semi-configurable constants... change on your own risk.;my_id equ isolinux_idFILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)FILENAME_MAX equ (1 << FILENAME_MAX_LG2)NULLFILE equ 0 ; Zero byte == null file nameNULLOFFSET equ 0 ; Position in which to lookretry_count equ 6 ; How patient are we with the BIOS?%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the topMAX_OPEN_LG2 equ 6 ; log2(Max number of open files)MAX_OPEN equ (1 << MAX_OPEN_LG2)SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)SECTOR_SIZE equ (1 << SECTOR_SHIFT);; 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.; 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;; Segment assignments in the bottom 640K; 0000h - main code/data segment (and BIOS segment);real_mode_seg equ 3000hvk_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;; File structure. This holds the information for each currently open file.; struc open_file_tfile_sector resd 1 ; Sector pointer (0 = structure free)file_left resd 1 ; Number of sectors left endstruc%ifndef DEPEND%if (open_file_t_size & (open_file_t_size-1))%error "open_file_t is not a power of 2"%endif%endif struc dir_tdir_lba resd 1 ; Directory start (LBA)dir_len resd 1 ; Length in bytesdir_clust resd 1 ; Length in clusters endstruc; ---------------------------------------------------------------------------; BEGIN CODE; ---------------------------------------------------------------------------;; Memory below this point is reserved for the BIOS and the MBR; section .earlybsstrackbufsize equ 8192trackbuf resb trackbufsize ; Track buffer goes heregetcbuf resb trackbufsize; ends at 4800h section .bss alignb 4ISOFileName resb 64 ; ISO filename canonicalization bufferISOFileNameEnd equ $CurDir resb dir_t_size ; Current directoryRootDir resb dir_t_size ; Root directoryFirstSecSum resd 1 ; Checksum of bytes 64-2048ImageDwords resd 1 ; isolinux.bin size, dwordsInitStack resd 1 ; Initial stack pointer (SS:SP)DiskSys resw 1 ; Last INT 13h callImageSectors resw 1 ; isolinux.bin size, sectorsDiskError resb 1 ; Error code for disk I/ODriveNo resb 1 ; CD-ROM BIOS drive numberISOFlags resb 1 ; Flags for ISO directory searchRetryCount resb 1 ; Used for disk access retries_spec_start equ $;; El Torito spec packet; alignb 8spec_packet: resb 1 ; Size of packetsp_media: resb 1 ; Media typesp_drive: resb 1 ; Drive numbersp_controller: resb 1 ; Controller indexsp_lba: resd 1 ; LBA for emulated disk imagesp_devspec: resw 1 ; IDE/SCSI informationsp_buffer: resw 1 ; User-provided buffersp_loadseg: resw 1 ; Load segmentsp_sectors: resw 1 ; Sector countsp_chs: resb 3 ; Simulated CHS geometrysp_dummy: resb 1 ; Scratch, safe to overwrite;; EBIOS drive parameter packet; alignb 8drive_params: resw 1 ; Buffer sizedp_flags: resw 1 ; Information flagsdp_cyl: resd 1 ; Physical cylindersdp_head: resd 1 ; Physical headsdp_sec: resd 1 ; Physical sectors/trackdp_totalsec: resd 2 ; Total sectorsdp_secsize: resw 1 ; Bytes per sectordp_dpte: resd 1 ; Device Parameter Tabledp_dpi_key: resw 1 ; 0BEDDh if rest validdp_dpi_len: resb 1 ; DPI len resb 1 resw 1dp_bus: resb 4 ; Host bus typedp_interface: resb 8 ; Interface typedb_i_path: resd 2 ; Interface pathdb_d_path: resd 2 ; Device path resb 1db_dpi_csum: resb 1 ; Checksum for DPI info;; EBIOS disk address packet; alignb 8dapa: resw 1 ; Packet size.count: resw 1 ; Block count.off: resw 1 ; Offset of buffer.seg: resw 1 ; Segment of buffer.lba: resd 2 ; LBA (LSW, MSW);; Spec packet for disk image emulation; alignb 8dspec_packet: resb 1 ; Size of packetdsp_media: resb 1 ; Media typedsp_drive: resb 1 ; Drive numberdsp_controller: resb 1 ; Controller indexdsp_lba: resd 1 ; LBA for emulated disk imagedsp_devspec: resw 1 ; IDE/SCSI informationdsp_buffer: resw 1 ; User-provided bufferdsp_loadseg: resw 1 ; Load segmentdsp_sectors: resw 1 ; Sector countdsp_chs: resb 3 ; Simulated CHS geometrydsp_dummy: resb 1 ; Scratch, safe to overwrite alignb 4_spec_end equ $_spec_len equ _spec_end - _spec_start alignb open_file_t_sizeFiles resb MAX_OPEN*open_file_t_size;; 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 section .text;;;; Primary entry point. Because BIOSes are buggy, we only load the first;; CD-ROM sector (2K) of the file, so the number one priority is actually;; loading the rest.;;StackBuf equ $bootsec equ $_start: ; Far jump makes sure we canonicalize the address cli jmp 0:_start1 times 8-($-$$) nop ; Pad to file offset 8 ; This table hopefully gets filled in by mkisofs using the ; -boot-info-table option. If not, the values in this ; table are default values that we can use to get us what ; we need, at least under a certain set of assumptions.bi_pvd: dd 16 ; LBA of primary volume descriptorbi_file: dd 0 ; LBA of boot filebi_length: dd 0xdeadbeef ; Length of boot filebi_csum: dd 0xdeadbeef ; Checksum of boot filebi_reserved: times 10 dd 0xdeadbeef ; Reserved_start1: mov [cs:InitStack],sp ; Save initial stack pointer mov [cs:InitStack+2],ss xor ax,ax mov ss,ax mov sp,StackBuf ; Set up stack mov ds,ax mov es,ax mov fs,ax mov gs,ax sti cld ; Show signs of life mov si,syslinux_banner call writestr%ifdef DEBUG_MESSAGES mov si,copyright_str call writestr%endif ; ; Before modifying any memory, get the checksum of bytes ; 64-2048 ;initial_csum: xor edi,edi mov si,_start1 mov cx,(SECTOR_SIZE-64) >> 2.loop: lodsd add edi,eax loop .loop mov [FirstSecSum],edi mov [DriveNo],dl%ifdef DEBUG_MESSAGES mov si,startup_msg call writemsg mov al,dl call writehex2 call crlf%endif ; ; Initialize spec packet buffers ; mov di,_spec_start mov cx,_spec_len >> 2 xor eax,eax rep stosd ; Initialize length field of the various packets mov byte [spec_packet],13h mov byte [drive_params],30 mov byte [dapa],16 mov byte [dspec_packet],13h ; Other nonzero fields inc word [dsp_sectors] ; Now figure out what we're actually doing ; Note: use passed-in DL value rather than 7Fh because ; at least some BIOSes will get the wrong value otherwise mov ax,4B01h ; Get disk emulation status mov dl,[DriveNo] mov si,spec_packet int 13h jc award_hack ; changed for BrokenAwardHack mov dl,[DriveNo] cmp [sp_drive],dl ; Should contain the drive number jne spec_query_failed%ifdef DEBUG_MESSAGES mov si,spec_ok_msg call writemsg mov al,byte [sp_drive] call writehex2 call crlf%endiffound_drive: ; Alright, we have found the drive. Now, try to find the ; boot file itself. If we have a boot info table, life is ; good; if not, we have to make some assumptions, and try ; to figure things out ourselves. In particular, the ; assumptions we have to make are: ; - single session only ; - only one boot entry (no menu or other alternatives) cmp dword [bi_file],0 ; Address of code to load jne found_file ; Boot info table present :)%ifdef DEBUG_MESSAGES mov si,noinfotable_msg call writemsg%endif ; No such luck. See if the the spec packet contained one. mov eax,[sp_lba] and eax,eax jz set_file ; Good enough%ifdef DEBUG_MESSAGES mov si,noinfoinspec_msg call writemsg%endif ; No such luck. Get the Boot Record Volume, assuming single ; session disk, and that we're the first entry in the chain mov eax,17 ; Assumed address of BRV mov bx,trackbuf call getonesec mov eax,[trackbuf+47h] ; Get boot catalog address mov bx,trackbuf call getonesec ; Get boot catalog mov eax,[trackbuf+28h] ; First boot entry ; And hope and pray this is us... ; Some BIOSes apparently have limitations on the size ; that may be loaded (despite the El Torito spec being very ; clear on the fact that it must all be loaded.) Therefore, ; we load it ourselves, and *bleep* the BIOS.set_file: mov [bi_file],eaxfound_file: ; Set up boot file sizes mov eax,[bi_length] sub eax,SECTOR_SIZE-3 shr eax,2 ; bytes->dwords mov [ImageDwords],eax ; boot file dwords add eax,(2047 >> 2) shr eax,9 ; dwords->sectors mov [ImageSectors],ax ; boot file sectors mov eax,[bi_file] ; Address of code to load inc eax ; Don't reload bootstrap code%ifdef DEBUG_MESSAGES mov si,offset_msg call writemsg call writehex8 call crlf%endif ; Just in case some BIOSes have problems with ; segment wraparound, use the normalized address mov bx,((7C00h+2048) >> 4) mov es,bx xor bx,bx mov bp,[ImageSectors]%ifdef DEBUG_MESSAGES push ax mov si,size_msg call writemsg mov ax,bp call writehex4 call crlf pop ax%endif call getlinsec push ds pop es%ifdef DEBUG_MESSAGES mov si,loaded_msg call writemsg%endif ; Verify the checksum on the loaded image.verify_image: mov si,7C00h+2048 mov bx,es mov ecx,[ImageDwords] mov edi,[FirstSecSum] ; First sector checksum.loop es lodsd add edi,eax dec ecx jz .done and si,si jnz .loop ; SI wrapped around, advance ES add bx,1000h mov es,bx jmp short .loop.done: mov ax,ds mov es,ax cmp [bi_csum],edi je integrity_ok mov si,checkerr_msg call writemsg jmp kaboomintegrity_ok:%ifdef DEBUG_MESSAGES mov si,allread_msg call writemsg%endif jmp all_read ; Jump to main code;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; There is a problem with certain versions of the AWARD BIOS ... ;; the boot sector will be loaded and executed correctly, but, because the;; int 13 vector points to the wrong code in the BIOS, every attempt to;; load the spec packet will fail. We scan for the equivalent of;;;; mov ax,0201h;; mov bx,7c00h;; mov cx,0006h;; mov dx,0180h;; pushf;; call <direct far>;;;; and use <direct far> as the new vector for int 13. The code above is;; used to load the boot code into ram, and there should be no reason;; for anybody to change it now or in the future. There are no opcodes;; that use encodings relativ to IP, so scanning is easy. If we find the;; code above in the BIOS code we can be pretty sure to run on a machine;; with an broken AWARD BIOS ... ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;%ifdef DEBUG_MESSAGES ;; ;;award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;award_not_orig db "BAH: Original Int 13 vector : ",0 ;;award_not_new db "BAH: Int 13 vector changed to : ",0 ;;award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;award_not_fail db "BAH: FAILURE" ;;award_not_crlf db CR,LF,0 ;; ;;%endif ;; ;;award_oldint13 dd 0 ;;award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;award_hack: mov si,spec_err_msg ; Moved to this place from call writemsg ; spec_query_faild ;%ifdef DEBUG_MESSAGES ; ; mov si,award_notice ; display our plan call writemsg ; mov si,award_not_orig ; display original int 13 call writemsg ; vector%endif ; mov eax,[13h*4] ; mov [award_oldint13],eax ; ;%ifdef DEBUG_MESSAGES ; ; call writehex8 ; mov si,award_not_crlf ; call writestr ;%endif ; push es ; save ES mov ax,0f000h ; ES = BIOS Seg mov es,ax ; cld ; xor di,di ; start at ES:DI = f000:0award_loop: push di ; save DI mov si,award_string ; scan for award_string mov cx,7 ; length of award_string = 7dw repz cmpsw ; compare pop di ; restore DI jcxz award_found ; jmp if found inc di ; not found, inc di jno award_loop ; ;award_failed: pop es ; No, not this way :-((award_fail2: ; ;%ifdef DEBUG_MESSAGES ; ; mov si,award_not_fail ; display failure ... call writemsg ;%endif ; mov eax,[award_oldint13] ; restore the original int or eax,eax ; 13 vector if there is one jz spec_query_failed ; and try other workarounds mov [13h*4],eax ; jmp spec_query_failed ; ;award_found: mov eax,[es:di+0eh] ; load possible int 13 addr pop es ; restore ES ; cmp eax,[award_oldint13] ; give up if this is the jz award_failed ; active int 13 vector, mov [13h*4],eax ; otherwise change 0:13h*4 ; ;%ifdef DEBUG_MESSAGES ; ; push eax ; display message and mov si,award_not_new ; new vector address call writemsg ; pop eax ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -