--- trunk/mkinitrd-magellan/isolinux/isolinux.asm 2010/08/19 08:27:19 1132 +++ trunk/mkinitrd-magellan/isolinux/isolinux.asm 2010/08/19 09:50:43 1133 @@ -1,5 +1,4 @@ ; -*- fundamental -*- (asm-mode sucks) -; $Id: isolinux.asm,v 1.1 2007-09-01 22:44:04 niro Exp $ ; **************************************************************************** ; ; isolinux.asm @@ -9,7 +8,8 @@ ; available. It is based on the SYSLINUX boot loader for MS-DOS ; floppies. ; -; Copyright (C) 1994-2005 H. Peter Anvin +; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved +; Copyright 2009 Intel Corporation; author: 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 @@ -20,12 +20,7 @@ ; **************************************************************************** %define IS_ISOLINUX 1 -%include "macros.inc" -%include "config.inc" -%include "kernel.inc" -%include "bios.inc" -%include "tracers.inc" -%include "layout.inc" +%include "head.inc" ; ; Some semi-configurable constants... change on your own risk. @@ -42,26 +37,19 @@ 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 +ROOT_DIR_WORD equ 0x002F ; ; 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. +; stick them in high memory and copy them down before we need them. ; struc vkernel vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** vk_rname: resb FILENAME_MAX ; Real name vk_appendlen: resw 1 +vk_type: resb 1 ; Type of file alignb 4 vk_append: resb max_cmd_len+1 ; Command line alignb 4 @@ -69,20 +57,13 @@ endstruc ; -; Segment assignments in the bottom 640K -; 0000h - main code/data segment (and BIOS segment) -; -real_mode_seg equ 3000h -vk_seg equ 2000h ; Virtual kernels -xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem -comboot_seg equ real_mode_seg ; COMBOOT image loading zone - -; ; File structure. This holds the information for each currently open file. ; struc open_file_t file_sector resd 1 ; Sector pointer (0 = structure free) +file_bytesleft resd 1 ; Number of bytes left file_left resd 1 ; Number of sectors left + resd 1 ; Unused endstruc %ifndef DEPEND @@ -107,32 +88,43 @@ section .earlybss trackbufsize equ 8192 trackbuf resb trackbufsize ; Track buffer goes here -getcbuf resb trackbufsize -; ends at 4800h +; ends at 2800h - section .bss + ; Some of these are touched before the whole image + ; is loaded. DO NOT move this to .uibss. + section .bss2 alignb 4 ISOFileName resb 64 ; ISO filename canonicalization buffer ISOFileNameEnd equ $ -CurDir resb dir_t_size ; Current directory +CurrentDir resb dir_t_size ; Current directory RootDir resb dir_t_size ; Root directory FirstSecSum resd 1 ; Checksum of bytes 64-2048 ImageDwords resd 1 ; isolinux.bin size, dwords InitStack resd 1 ; Initial stack pointer (SS:SP) DiskSys resw 1 ; Last INT 13h call ImageSectors resw 1 ; isolinux.bin size, sectors +; These following two are accessed as a single dword... +GetlinsecPtr resw 1 ; The sector-read pointer +BIOSName resw 1 ; Display string for BIOS type +%define HAVE_BIOSNAME 1 +BIOSType resw 1 DiskError resb 1 ; Error code for disk I/O -DriveNo resb 1 ; CD-ROM BIOS drive number +DriveNumber resb 1 ; CD-ROM BIOS drive number ISOFlags resb 1 ; Flags for ISO directory search RetryCount resb 1 ; Used for disk access retries -_spec_start equ $ + alignb 8 +bsHidden resq 1 ; Used in hybrid mode +bsSecPerTrack resw 1 ; Used in hybrid mode +bsHeads resw 1 ; Used in hybrid mode + ; ; El Torito spec packet ; alignb 8 +_spec_start equ $ spec_packet: resb 1 ; Size of packet sp_media: resb 1 ; Media type sp_drive: resb 1 ; Drive number @@ -142,7 +134,7 @@ sp_buffer: resw 1 ; User-provided buffer sp_loadseg: resw 1 ; Load segment sp_sectors: resw 1 ; Sector count -sp_chs: resb 3 ; Simulated CHS geometry +sp_chs: resb 3 ; Simulated CHS geometry sp_dummy: resb 1 ; Scratch, safe to overwrite ; @@ -201,24 +193,16 @@ alignb open_file_t_size Files 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 change -xbs_vgabuf equ trackbufsize -xbs_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 $ +StackBuf equ STACK_TOP-44 ; 44 bytes needed for + ; the bootsector chainloading + ; code! +OrigESDI equ StackBuf-4 ; The high dword on the stack bootsec equ $ @@ -236,40 +220,94 @@ bi_length: dd 0xdeadbeef ; Length of boot file bi_csum: dd 0xdeadbeef ; Checksum of boot file bi_reserved: times 10 dd 0xdeadbeef ; Reserved +bi_end: -_start1: mov [cs:InitStack],sp ; Save initial stack pointer + ; Custom entry point for the hybrid-mode disk. + ; The following values will have been pushed onto the + ; entry stack: + ; - partition offset (qword) + ; - ES + ; - DI + ; - DX (including drive number) + ; - CBIOS Heads + ; - CBIOS Sectors + ; - EBIOS flag + ; (top of stack) + ; + ; If we had an old isohybrid, the partition offset will + ; be missing; we can check for that with sp >= 0x7c00. + ; Serious hack alert. +%ifndef DEBUG_MESSAGES +_hybrid_signature: + dd 0x7078c0fb ; An arbitrary number... + +_start_hybrid: + pop cx ; EBIOS flag + pop word [cs:bsSecPerTrack] + pop word [cs:bsHeads] + pop dx + pop di + pop es + xor eax,eax + xor ebx,ebx + cmp sp,7C00h + jae .nooffset + pop eax + pop ebx +.nooffset: + mov [cs:bsHidden],eax + mov [cs:bsHidden+4],ebx + + mov si,bios_cbios + jcxz _start_common + mov si,bios_ebios + jmp _start_common +%endif + +_start1: + mov si,bios_cdrom +_start_common: + 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 sp,StackBuf ; Set up stack + push es ; Save initial ES:DI -> $PnP pointer + push di mov ds,ax mov es,ax mov fs,ax mov gs,ax sti - cld + + mov [BIOSType],si + mov eax,[si] + mov [GetlinsecPtr],eax + ; Show signs of life mov si,syslinux_banner - call writestr + call writestr_early %ifdef DEBUG_MESSAGES mov si,copyright_str - call writestr +%else + mov si,[BIOSName] %endif + call writestr_early ; ; Before modifying any memory, get the checksum of bytes ; 64-2048 ; initial_csum: xor edi,edi - mov si,_start1 + mov si,bi_end mov cx,(SECTOR_SIZE-64) >> 2 .loop: lodsd add edi,eax loop .loop mov [FirstSecSum],edi - mov [DriveNo],dl + mov [DriveNumber],dl %ifdef DEBUG_MESSAGES mov si,startup_msg call writemsg @@ -294,15 +332,19 @@ ; Other nonzero fields inc word [dsp_sectors] + ; Are we just pretending to be a CD-ROM? + cmp word [BIOSType],bios_cdrom + jne found_drive ; If so, no spec packet... + ; 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 dl,[DriveNumber] mov si,spec_packet - int 13h + call int13 jc award_hack ; changed for BrokenAwardHack - mov dl,[DriveNo] + mov dl,[DriveNumber] cmp [sp_drive],dl ; Should contain the drive number jne spec_query_failed @@ -330,8 +372,8 @@ mov si,noinfotable_msg call writemsg %endif - - ; No such luck. See if the the spec packet contained one. + + ; No such luck. See if the spec packet contained one. mov eax,[sp_lba] and eax,eax jz set_file ; Good enough @@ -340,9 +382,9 @@ 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 + ; session disk, and that we're the first entry in the chain. mov eax,17 ; Assumed address of BRV mov bx,trackbuf call getonesec @@ -354,7 +396,7 @@ mov eax,[trackbuf+28h] ; First boot entry ; And hope and pray this is us... - ; Some BIOSes apparently have limitations on the size + ; 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. @@ -365,7 +407,7 @@ found_file: ; Set up boot file sizes mov eax,[bi_length] - sub eax,SECTOR_SIZE-3 + sub eax,SECTOR_SIZE-3 ; ... minus sector loaded shr eax,2 ; bytes->dwords mov [ImageDwords],eax ; boot file dwords add eax,(2047 >> 2) @@ -442,7 +484,7 @@ ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; There is a problem with certain versions of the AWARD BIOS ... +;; 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 @@ -459,7 +501,7 @@ ;; 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 ... +;; with an broken AWARD BIOS ... ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; @@ -478,8 +520,8 @@ 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 +award_hack: mov si,spec_err_msg ; Moved to this place from + call writemsg ; spec_query_faild ; %ifdef DEBUG_MESSAGES ; ; @@ -494,22 +536,22 @@ %ifdef DEBUG_MESSAGES ; ; call writehex8 ; - mov si,award_not_crlf ; - call writestr ; + mov si,award_not_crlf ; + call writestr_early ; %endif ; push es ; save ES - mov ax,0f000h ; ES = BIOS Seg - mov es,ax ; - cld ; - xor di,di ; start at ES:DI = f000:0 -award_loop: push di ; save DI - mov si,award_string ; scan for award_string + mov ax,0f000h ; ES = BIOS Seg + mov es,ax ; + cld ; + xor di,di ; start at ES:DI = f000:0 +award_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 ; + 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: ; @@ -535,18 +577,18 @@ ; %ifdef DEBUG_MESSAGES ; ; - push eax ; display message and + push eax ; display message and mov si,award_not_new ; new vector address call writemsg ; pop eax ; call writehex8 ; mov si,award_not_crlf ; - call writestr ; + call writestr_early ; %endif ; - mov ax,4B01h ; try to read the spec packet - mov dl,[DriveNo] ; now ... it should not fail - mov si,spec_packet ; any longer - int 13h ; + mov ax,4B01h ; try to read the spec packet + mov dl,[DriveNumber] ; now ... it should not fail + mov si,spec_packet ; any longer + int 13h ; jc award_fail2 ; ; %ifdef DEBUG_MESSAGES ; @@ -572,8 +614,8 @@ .test_loop: pusha mov ax,4B01h mov si,spec_packet - mov byte [si],13 ; Size of buffer - int 13h + mov byte [si],13h ; Size of buffer + call int13 popa jc .still_broken @@ -589,16 +631,24 @@ ; Okay, good enough... mov si,alright_msg call writemsg - mov [DriveNo],dl +.found_drive0: mov [DriveNumber],dl .found_drive: jmp found_drive ; Award BIOS 4.51 apparently passes garbage in sp_drive, ; but if this was the drive number originally passed in ; DL then consider it "good enough" .maybe_broken: - cmp byte [DriveNo],dl + mov al,[DriveNumber] + cmp al,dl je .found_drive + ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02 + ; passes garbage in sp_drive, and the drive number originally + ; passed in DL does not have 80h bit set. + or al,80h + cmp al,dl + je .found_drive0 + .still_broken: dec dx cmp dl, 80h jnb .test_loop @@ -608,7 +658,7 @@ ; 4B01h, so we can't query a spec packet no matter ; what. If we got a drive number in DL, then try to ; use it, and if it works, then well... - mov dl,[DriveNo] + mov dl,[DriveNumber] cmp dl,81h ; Should be 81-FF at least jb fatal_error ; If not, it's hopeless @@ -634,10 +684,10 @@ writemsg: push ax push si mov si,isolinux_str - call writestr + call writestr_early pop si - call writestr - pop ax + call writestr_early + pop ax ret ; @@ -660,6 +710,29 @@ ret ; +; int13: save all the segment registers and call INT 13h. +; Some CD-ROM BIOSes have been found to corrupt segment registers +; and/or disable interrupts. +; +int13: + pushf + push bp + push ds + push es + push fs + push gs + int 13h + mov bp,sp + setc [bp+10] ; Propagate CF to the caller + pop gs + pop fs + pop es + pop ds + pop bp + popf + ret + +; ; Get one sector. Convenience entry point. ; getonesec: @@ -669,30 +742,211 @@ ; ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. ; -; Note that we can't always do this as a single request, because at least -; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick -; to 32 sectors (64K) per request. -; ; Input: ; EAX - Linear sector number ; ES:BX - Target buffer ; BP - Sector count ; -getlinsec: +getlinsec: jmp word [cs:GetlinsecPtr] + +%ifndef DEBUG_MESSAGES + +; +; First, the variants that we use when actually loading off a disk +; (hybrid mode.) These are adapted versions of the equivalent routines +; in ldlinux.asm. +; + +; +; getlinsec_ebios: +; +; getlinsec implementation for floppy/HDD EBIOS (EDD) +; +getlinsec_ebios: + xor edx,edx + shld edx,eax,2 + shl eax,2 ; Convert to HDD sectors + add eax,[bsHidden] + adc edx,[bsHidden+4] + shl bp,2 + +.loop: + push bp ; Sectors left +.retry2: + call maxtrans ; Enforce maximum transfer size + movzx edi,bp ; Sectors we are about to read + mov cx,retry_count +.retry: + + ; Form DAPA on stack + push edx + push eax + push es + push bx + push di + push word 16 + mov si,sp + pushad + mov dl,[DriveNumber] + push ds + push ss + pop ds ; DS <- SS + mov ah,42h ; Extended Read + call int13 + pop ds + popad + lea sp,[si+16] ; Remove DAPA + jc .error + pop bp + add eax,edi ; Advance sector pointer + adc edx,0 + sub bp,di ; Sectors left + shl di,9 ; 512-byte sectors + add bx,di ; Advance buffer pointer + and bp,bp + jnz .loop + + ret + +.error: + ; Some systems seem to get "stuck" in an error state when + ; using EBIOS. Doesn't happen when using CBIOS, which is + ; good, since some other systems get timeout failures + ; waiting for the floppy disk to spin up. + + pushad ; Try resetting the device + xor ax,ax + mov dl,[DriveNumber] + call int13 + popad + loop .retry ; CX-- and jump if not zero + + ;shr word [MaxTransfer],1 ; Reduce the transfer size + ;jnz .retry2 + + ; Total failure. Try falling back to CBIOS. + mov word [GetlinsecPtr], getlinsec_cbios + ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer + + pop bp + jmp getlinsec_cbios.loop + +; +; getlinsec_cbios: +; +; getlinsec implementation for legacy CBIOS +; +getlinsec_cbios: + xor edx,edx + shl eax,2 ; Convert to HDD sectors + add eax,[bsHidden] + shl bp,2 + +.loop: + push edx + push eax + push bp + push bx + + movzx esi,word [bsSecPerTrack] + movzx edi,word [bsHeads] + ; + ; Dividing by sectors to get (track,sector): we may have + ; up to 2^18 tracks, so we need to use 32-bit arithmetric. + ; + div esi + xor cx,cx + xchg cx,dx ; CX <- sector index (0-based) + ; EDX <- 0 + ; eax = track # + div edi ; Convert track to head/cyl + + ; We should test this, but it doesn't fit... + ; cmp eax,1023 + ; ja .error + + ; + ; Now we have AX = cyl, DX = head, CX = sector (0-based), + ; BP = sectors to transfer, SI = bsSecPerTrack, + ; ES:BX = data target + ; + + call maxtrans ; Enforce maximum transfer size + + ; Must not cross track boundaries, so BP <= SI-CX + sub si,cx + cmp bp,si + jna .bp_ok + mov bp,si +.bp_ok: + + shl ah,6 ; Because IBM was STOOPID + ; and thought 8 bits were enough + ; then thought 10 bits were enough... + inc cx ; Sector numbers are 1-based, sigh + or cl,ah + mov ch,al + mov dh,dl + mov dl,[DriveNumber] + xchg ax,bp ; Sector to transfer count + mov ah,02h ; Read sectors + mov bp,retry_count +.retry: + pushad + call int13 + popad + jc .error +.resume: + movzx ecx,al ; ECX <- sectors transferred + shl ax,9 ; Convert sectors in AL to bytes in AX + pop bx + add bx,ax + pop bp + pop eax + pop edx + add eax,ecx + sub bp,cx + jnz .loop + ret + +.error: + dec bp + jnz .retry + + xchg ax,bp ; Sectors transferred <- 0 + shr word [MaxTransfer],1 + jnz .resume + jmp disk_error + +; +; Truncate BP to MaxTransfer +; +maxtrans: + cmp bp,[MaxTransfer] + jna .ok + mov bp,[MaxTransfer] +.ok: ret + +%endif + +; +; This is the variant we use for real CD-ROMs: +; LBA, 2K sectors, some special error handling. +; +getlinsec_cdrom: mov si,dapa ; Load up the DAPA mov [si+4],bx - mov bx,es - mov [si+6],bx + mov [si+6],es mov [si+8],eax .loop: push bp ; Sectors left - cmp bp,[MaxTransfer] + cmp bp,[MaxTransferCD] jbe .bp_ok - mov bp,[MaxTransfer] + mov bp,[MaxTransferCD] .bp_ok: mov [si+2],bp push si - mov dl,[DriveNo] + mov dl,[DriveNumber] mov ah,42h ; Extended Read call xint13 pop si @@ -710,7 +964,7 @@ ; INT 13h with retry xint13: mov byte [RetryCount],retry_count .try: pushad - int 13h + call int13 jc .error add sp,byte 8*4 ; Clean up stack ret @@ -733,7 +987,7 @@ shr ah,1 ; Otherwise, try to reduce adc ah,0 ; the max transfer size, but not to 0 .setsize: - mov [MaxTransfer],ah + mov [MaxTransferCD],ah mov [dapa+2],ah .again: pop ax @@ -744,11 +998,11 @@ mov al,[DiskError] call writehex2 mov si,oncall_str - call writestr + call writestr_early mov ax,[DiskSys] call writehex4 mov si,ondrive_str - call writestr + call writestr_early mov al,dl call writehex2 call crlf @@ -758,16 +1012,11 @@ ; kaboom: write a message and bail out. Wait for a user keypress, ; then do a hard reboot. ; +disk_error: kaboom: - lss sp,[cs:StackPtr] - mov ax,cs - mov ds,ax - mov es,ax - mov fs,ax - mov gs,ax - sti + RESET_STACK_AND_SEGS AX mov si,err_bootfailed - call cwritestr + call writestr call getchar cli mov word [BIOS_magic],0 ; Cold reboot @@ -778,22 +1027,23 @@ ; ----------------------------------------------------------------------------- %include "writestr.inc" ; String output -writestr equ cwritestr +writestr_early equ writestr %include "writehex.inc" ; Hexadecimal output ; ----------------------------------------------------------------------------- ; Data that needs to be in the first sector ; ----------------------------------------------------------------------------- -syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0 -copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' - db CR, LF, 0 +syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0 +copyright_str db ' Copyright (C) 1994-' + asciidec YEAR + db ' H. Peter Anvin et al', CR, LF, 0 isolinux_str db 'isolinux: ', 0 %ifdef DEBUG_MESSAGES startup_msg: db 'Starting up, DL = ', 0 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 -secsize_msg: db 'Sector size appears to be ', 0 -offset_msg: db 'Loading main image from LBA = ', 0 +secsize_msg: db 'Sector size ', 0 +offset_msg: db 'Main image LBA = ', 0 size_msg: db 'Sectors to load = ', 0 loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 verify_msg: db 'Image checksum verified.', CR, LF, 0 @@ -803,8 +1053,8 @@ noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0 maybe_msg: db 'Found something at drive = ', 0 -alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0 -nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0 +alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0 +nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0 diskerr_msg: db 'Disk error ', 0 @@ -817,44 +1067,34 @@ crlf_msg db CR, LF null_msg db 0 - alignb 4, db 0 -StackPtr dw StackBuf, 0 ; SS:SP for stack reset -MaxTransfer dw 32 ; Max sectors per transfer +bios_cdrom_str db 'ETCD', 0 +%ifndef DEBUG_MESSAGES +bios_cbios_str db 'CHDD', 0 +bios_ebios_str db 'EHDD' ,0 +%endif + + alignz 4 +bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str +%ifndef DEBUG_MESSAGES +bios_cbios: dw getlinsec_cbios, bios_cbios_str +bios_ebios: dw getlinsec_ebios, bios_ebios_str +%endif + +; Maximum transfer size +MaxTransfer dw 127 ; Hard disk modes +MaxTransferCD dw 32 ; CD mode rl_checkpt equ $ ; Must be <= 800h -rl_checkpt_off equ ($-$$) -;%ifndef DEPEND -;%if rl_checkpt_off > 0x800 -;%error "Sector 0 overflow" -;%endif -;%endif + ; This pads to the end of sector 0 and errors out on + ; overflow. + times 2048-($-$$) db 0 ; ---------------------------------------------------------------------------- ; End of code and data that have to be in the first sector ; ---------------------------------------------------------------------------- all_read: -; -; Initialize screen (if we're using one) -; - ; Now set up screen parameters - call adjust_screen - - ; Wipe the F-key area - mov al,NULLFILE - mov di,FKeyName - mov cx,10*(1 << FILENAME_MAX_LG2) - rep stosb - - ; Patch the writechr routine to point to the full code - mov word [writechr+1], writechr_full-(writechr+3) - -; Tell the user we got this far... -%ifndef DEBUG_MESSAGES ; Gets messy with debugging on - mov si,copyright_str - call writestr -%endif ; Test tracers TRACER 'T' @@ -866,6 +1106,15 @@ %include "init.inc" %include "cpuinit.inc" + ; Patch the writechr routine to point to the full code + mov word [writechr+1], writechr_full-(writechr+3) + +; Tell the user we got this far... +%ifndef DEBUG_MESSAGES ; Gets messy with debugging on + mov si,copyright_str + call writestr_early +%endif + ; ; Now we're all set to start with our *real* business. First load the ; configuration file (if any) and parse it. @@ -885,7 +1134,7 @@ ; mkisofs gave us a pointer to the primary volume descriptor ; (which will be at 16 only for a single-session disk!); from the PVD ; we should be able to find the rest of what we need to know. -; +; get_fs_structures: mov eax,[bi_pvd] mov bx,trackbuf @@ -893,7 +1142,7 @@ mov eax,[trackbuf+156+2] mov [RootDir+dir_lba],eax - mov [CurDir+dir_lba],eax + mov [CurrentDir+dir_lba],eax %ifdef DEBUG_MESSAGES mov si,dbg_rootdir_msg call writemsg @@ -901,31 +1150,49 @@ call crlf %endif mov eax,[trackbuf+156+10] - mov [RootDir+dir_len],eax - mov [CurDir+dir_len],eax + mov [RootDir+dir_len],eax + mov [CurrentDir+dir_len],eax add eax,SECTOR_SIZE-1 shr eax,SECTOR_SHIFT mov [RootDir+dir_clust],eax - mov [CurDir+dir_clust],eax + mov [CurrentDir+dir_clust],eax ; Look for an isolinux directory, and if found, ; make it the current directory instead of the root ; directory. + ; Also copy the name of the directory to CurrentDirName + mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName mov di,boot_dir ; Search for /boot/isolinux mov al,02h + push di call searchdir_iso + pop di jnz .found_dir mov di,isolinux_dir mov al,02h ; Search for /isolinux + push di call searchdir_iso + pop di jz .no_isolinux_dir .found_dir: - mov [CurDir+dir_len],eax + ; Copy current directory name to CurrentDirName + push si + push di + mov si,di + mov di,CurrentDirName + call strcpy + mov byte [di],0 ;done in case it's not word aligned + dec di + mov byte [di],'/' + pop di + pop si + + mov [CurrentDir+dir_len],eax mov eax,[si+file_left] - mov [CurDir+dir_clust],eax + mov [CurrentDir+dir_clust],eax xor eax,eax ; Free this file pointer entry xchg eax,[si+file_sector] - mov [CurDir+dir_lba],eax + mov [CurrentDir+dir_lba],eax %ifdef DEBUG_MESSAGES push si mov si,dbg_isodir_msg @@ -945,7 +1212,11 @@ call writemsg %endif - mov di,isolinux_cfg + mov si,config_name + mov di,ConfigName + call strcpy + + mov di,ConfigName call open jz no_config_file ; Not found or empty @@ -961,25 +1232,8 @@ %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" - -; -; Enable disk emulation. The kind of disk we emulate is dependent on the size of -; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. +; Enable disk emulation. The kind of disk we emulate is dependent on the +; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. ; is_disk_image: TRACER CR @@ -987,8 +1241,7 @@ TRACER 'D' TRACER ':' - shl edx,16 - mov dx,ax ; Set EDX <- file size + mov edx,eax ; File size mov di,img_table mov cx,img_table_count mov eax,[si+file_sector] ; Starting LBA of file @@ -1012,7 +1265,7 @@ mov bx,trackbuf mov cx,1 ; Load 1 sector call getfssec - + cmp word [trackbuf+510],0aa55h ; Boot signature jne .bad_image ; Image not bootable @@ -1031,7 +1284,7 @@ .part_loop: add di,byte 16 loop .part_scan - + push eax ; H/S push edx ; File size mov bl,ah @@ -1080,16 +1333,16 @@ mov ax,4C00h ; Enable emulation and boot mov si,dspec_packet - mov dl,[DriveNo] + mov dl,[DriveNumber] lss sp,[InitStack] TRACER 'X' - int 13h + call int13 ; If this returns, we have problems .bad_image: mov si,err_disk_image - call cwritestr + call writestr jmp enter_command ; @@ -1109,49 +1362,16 @@ .done_sector: ret ; -; Boot a specified local disk. AX specifies the BIOS disk number; or -; 0xFFFF in case we should execute INT 18h ("next device.") +; close_file: +; Deallocates a file structure (pointer in SI) +; Assumes CS == DS. ; -local_boot: - call vgaclearmode - lss sp,[cs:Stack] ; Restore stack pointer - xor dx,dx - mov ds,dx - mov es,dx - mov fs,dx - mov gs,dx - mov si,localboot_msg - call writestr - cmp ax,-1 - je .int18 - - ; Load boot sector from the specified BIOS device and jump to it. - mov dl,al - xor dh,dh - push dx - xor ax,ax ; Reset drive - call xint13 - mov ax,0201h ; Read one sector - mov cx,0001h ; C/H/S = 0/0/1 (first sector) - mov bx,trackbuf - call xint13 - pop dx - cli ; Abandon hope, ye who enter here - mov si,trackbuf - mov di,07C00h - mov cx,512 ; Probably overkill, but should be safe - rep movsd - lss sp,[cs:InitStack] - jmp 0:07C00h ; Jump to new boot sector - -.int18: - int 18h ; Hope this does the right thing... - jmp kaboom ; If we returned, oh boy... - -; -; Abort loading code -; -%include "abort.inc" +close_file: + and si,si + jz .closed + mov dword [si],0 ; First dword == file_left + xor si,si +.closed: ret ; ; searchdir: @@ -1163,7 +1383,7 @@ ; If successful: ; ZF clear ; SI = file pointer -; DX:AX or EAX = file length in bytes +; EAX = file length in bytes ; If unsuccessful ; ZF set ; @@ -1187,7 +1407,7 @@ push es push ds pop es ; ES = DS - mov si,CurDir + mov si,CurrentDir cmp byte [di],'/' ; If filename begins with slash jne .not_rooted inc di ; Skip leading slash @@ -1195,6 +1415,8 @@ .not_rooted: mov eax,[si+dir_clust] mov [bx+file_left],eax + shl eax,SECTOR_SHIFT + mov [bx+file_bytesleft],eax mov eax,[si+dir_lba] mov [bx+file_sector],eax mov edx,[si+dir_len] @@ -1275,14 +1497,14 @@ mov eax,[si+2] ; Location of extent mov [bx+file_sector],eax mov eax,[si+10] ; Data length + mov [bx+file_bytesleft],eax push eax add eax,SECTOR_SIZE-1 shr eax,SECTOR_SHIFT mov [bx+file_left],eax pop eax - mov edx,eax - shr edx,16 - and bx,bx ; ZF = 0 + jz .failure ; Empty file? + ; ZF = 0 mov si,bx pop es ret @@ -1320,7 +1542,7 @@ ret ; -; iso_compare_names: +; iso_compare_names: ; Compare the names DS:SI and DS:DI and report if they are ; equal from an ISO 9660 perspective. SI is the name from ; the filesystem; CX indicates its length, and ';' terminates. @@ -1373,14 +1595,16 @@ ; ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed ; to by ES:DI; ends on encountering any whitespace. +; DI is preserved. ; ; This verifies that a filename is < FILENAME_MAX characters, ; doesn't contain whitespace, zero-pads the output buffer, ; and removes trailing dots and redundant slashes, ; so "repe cmpsb" can do a compare, and the ; path-searching routine gets a bit of an easier job. -; +; mangle_name: + push di push bx xor ax,ax mov cx,FILENAME_MAX-1 @@ -1401,9 +1625,9 @@ .mn_end: cmp bx,di ; At the beginning of the buffer? jbe .mn_zero - cmp byte [di-1],'.' ; Terminal dot? + cmp byte [es:di-1],'.' ; Terminal dot? je .mn_kill - cmp byte [di-1],'/' ; Terminal slash? + cmp byte [es:di-1],'/' ; Terminal slash? jne .mn_zero .mn_kill: dec di ; If so, remove it inc cx @@ -1413,14 +1637,13 @@ xor ax,ax ; Zero-fill name rep stosb pop bx + pop di ret ; Done ; ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled ; filename to the conventional representation. This is needed ; for the BOOT_IMAGE= parameter for the kernel. -; NOTE: A 13-byte buffer is mandatory, even if the string is -; known to be shorter. ; ; DS:SI -> input mangled file name ; ES:DI -> output buffer @@ -1442,10 +1665,10 @@ ; On exit: ; SI -> File pointer (or 0 on EOF) ; CF = 1 -> Hit EOF +; ECX -> Bytes actually read ; getfssec: TRACER 'F' - push ds push cs pop ds ; DS <- CS @@ -1456,26 +1679,29 @@ mov ecx,[si+file_left] .ok_size: - mov bp,cx - push cx - push si + pushad mov eax,[si+file_sector] + mov bp,cx TRACER 'l' call getlinsec - xor ecx,ecx - pop si - pop cx + popad + ; ECX[31:16] == 0 here... add [si+file_sector],ecx sub [si+file_left],ecx - ja .not_eof ; CF = 0 - - xor ecx,ecx - mov [si+file_sector],ecx ; Mark as unused - xor si,si + shl ecx,SECTOR_SHIFT ; Convert to bytes + cmp ecx,[si+file_bytesleft] + jb .not_all + mov ecx,[si+file_bytesleft] +.not_all: sub [si+file_bytesleft],ecx + jnz .ret ; CF = 0 in this case... + push eax + xor eax,eax + mov [si+file_sector],eax ; Unused + mov si,ax + pop eax stc - -.not_eof: +.ret: pop ds TRACER 'f' ret @@ -1486,6 +1712,7 @@ %include "getc.inc" ; getc et al %include "conio.inc" ; Console I/O +%include "configinit.inc" ; Initialize configuration %include "parseconfig.inc" ; High-level config file handling %include "parsecmd.inc" ; Low-level config file handling %include "bcopy32.inc" ; 32-bit bcopy @@ -1495,6 +1722,9 @@ %include "highmem.inc" ; High memory sizing %include "strcpy.inc" ; strcpy() %include "rawcon.inc" ; Console I/O w/o using the console functions +%include "idle.inc" ; Idle handling +%include "adv.inc" ; Auxillary Data Vector +%include "localboot.inc" ; Disk-based local boot ; ----------------------------------------------------------------------------- ; Begin data section @@ -1502,48 +1732,11 @@ section .data -boot_prompt db 'boot: ', 0 -wipe_char db BS, ' ', BS, 0 -err_notfound db 'Could not find kernel image: ',0 -err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 -err_noram db 'It appears your computer has less than ' - asciidec dosram_k - db 'K of low ("DOS")' - db CR, LF - db 'RAM. Linux needs at least this amount to boot. If you get' - db CR, LF - db 'this message in error, hold down the Ctrl key while' - db CR, LF - db 'booting, and I will take your word for it.', CR, LF, 0 -err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 -err_noparm db 'Missing parameter in config file.', CR, LF, 0 -err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 -err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 -err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 -err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' - db CR, LF, 0 -err_notdos db ': attempted DOS system call', CR, LF, 0 -err_comlarge db 'COMBOOT image too large.', CR, LF, 0 -err_bssimage db 'BSS images not supported.', CR, LF, 0 -err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 -notfound_msg db 'not found', CR, LF, 0 -localboot_msg db 'Booting from local disk...', CR, LF, 0 -cmdline_msg db 'Command line: ', CR, LF, 0 -ready_msg db 'Ready.', CR, LF, 0 -trying_msg db 'Trying to load: ', 0 -crlfloading_msg db CR, LF ; Fall through -loading_msg db 'Loading ', 0 -dotdot_msg db '.' -dot_msg db '.', 0 -fourbs_msg db BS, BS, BS, BS, 0 -aborted_msg db ' aborted.', CR, LF, 0 -crff_msg db CR, FF, 0 default_str db 'default', 0 default_len equ ($-default_str) boot_dir db '/boot' ; /boot/isolinux isolinux_dir db '/isolinux', 0 -ConfigName equ $ -isolinux_cfg db 'isolinux.cfg', 0 +config_name db 'isolinux.cfg', 0 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 %ifdef DEBUG_MESSAGES @@ -1552,12 +1745,6 @@ dbg_config_msg db 'About to load config file...', CR, LF, 0 dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 %endif -; -; Command line options we'd like to take a look at -; -; mem= and vga= are handled as normal 32-bit integer values -initrd_cmd db 'initrd=' -initrd_cmd_len equ 7 ; ; Config file keyword table @@ -1567,7 +1754,7 @@ ; ; Extensions to search for (in *forward* order). ; - align 4, db 0 + alignz 4 exten_table: db '.cbt' ; COMBOOT (specific) db '.img' ; Disk image db '.bin' ; CD boot sector @@ -1579,7 +1766,7 @@ ; ; Floppy image table ; - align 4, db 0 + alignz 4 img_table_count equ 3 img_table: dd 1200*1024 ; 1200K floppy @@ -1610,11 +1797,9 @@ ; **** ISOLINUX:: We may have to make this flexible, based on what the ; **** BIOS expects our "sector size" to be. ; - alignb 4, db 0 + alignz 4 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf -BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? BufSafeBytes dw trackbufsize ; = how many bytes? -EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes %ifndef DEPEND %if ( trackbufsize % SECTOR_SIZE ) != 0 %error trackbufsize must be a multiple of SECTOR_SIZE