📄 isobtrt.asm
字号:
;
; allocate_file: Allocate a file structure
;
; If successful:
; ZF set
; BX = file pointer
; In unsuccessful:
; ZF clear
;
allocate_file:
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
;
; 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.
; DI is expected to end with a null.
;
; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
;
iso_compare_names:
; First, terminate and canonicalize input filename
push di
mov di, ISOFileName
.canon_loop:
jcxz .canon_end
lodsb
dec cx
cmp al, ';'
je .canon_end
and al, al
je .canon_end
stosb
cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun
jb .canon_loop
.canon_end:
cmp di, ISOFileName
jbe .canon_done
cmp byte [di-1], '.' ; Remove terminal dots
jne .canon_done
dec di
jmp short .canon_end
.canon_done:
mov [di], byte 0 ; Null-terminate string
pop di
mov si, ISOFileName
.compare:
lodsb
mov ah, [di]
inc di
and ax, ax
jz .success ; End of string for both
and al, al ; Is either one end of string?
jz .failure ; If so, failure
and ah, ah
jz .failure
or ax, 2020h ; Convert to lower case
cmp al, ah
je .compare
.failure:
and ax, ax ; ZF = 0 (at least one will be nonzero)
.success:
ret
;
; getfssec: Get multiple clusters from a file, given the file pointer.
;
; On entry:
; ES:BX -> Buffer
; SI -> File pointer
; CX -> Cluster count; 0FFFFh = until end of file
; On exit:
; SI -> File pointer (or 0 on EOF)
; CF = 1 -> Hit EOF
;
getfssec:
cmp cx, [si+file_left]
jna .ok_size
mov cx, [si+file_left]
.ok_size:
mov bp, cx
push cx
push si
mov eax, [si+file_sector]
call getlinsec
xor ecx, ecx
pop si
pop cx
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
stc
.not_eof:
ret
; INT 13h, AX=4B01h, DL=<passed in value> failed.
; Try to scan the entire 80h-FFh from the end.
spec_query_failed:
mov si,spec_err_msg
call writemsg
mov dl, 0FFh
.test_loop:
pusha
mov ax, 4B01h
mov si, spec_packet
mov byte [si], 13 ; Size of buffer
int 13h
popa
jc .still_broken
mov si, maybe_msg
call writemsg
mov al, dl
call writehex2
call crlf
cmp byte [sp_drive], dl
jne .maybe_broken
; Okay, good enough...
mov si, alright_msg
call writemsg
mov [DriveNo], 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
je .found_drive
.still_broken:
dec dx
cmp dl, 80h
jnb .test_loop
fatal_error:
mov si, nothing_msg
call writemsg
.norge:
jmp short .norge
; Information message (DS:SI) output
; Prefix with "isolinux: "
;
writemsg:
push ax
push si
mov si, isolinux_str
call writestr
pop si
call writestr
pop ax
ret
;
; crlf: Print a newline
;
crlf:
mov si, crlf_msg
; Fall through
;
; writestr: write a null-terminated string to the console, saving
; registers on entry.
;
writestr:
pushfd
pushad
.top:
lodsb
and al, al
jz .end
call writechr
jmp short .top
.end:
popad
popfd
ret
;
; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
;
writehex2:
pushfd
pushad
shl eax, 24
mov cx, 2
jmp short writehex_common
writehex4:
pushfd
pushad
shl eax, 16
mov cx, 4
jmp short writehex_common
writehex8:
pushfd
pushad
mov cx, 8
writehex_common:
.loop:
rol eax, 4
push eax
and al, 0Fh
cmp al, 10
jae .high
.low:
add al, '0'
jmp short .ischar
.high:
add al, 'A'-10
.ischar:
call writechr
pop eax
loop .loop
popad
popfd
ret
;
; Write a character to the screen. There is a more "sophisticated"
; version of this in the subsequent code, so we patch the pointer
; when appropriate.
;
writechr:
pushfd
pushad
mov ah, 0Eh
xor bx, bx
int 10h
popad
popfd
ret
;
; Get one sector. Convenience entry point.
;
getonesec:
mov bp, 1
; Fall through to getlinsec
;
; 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:
mov si,dapa ; Load up the DAPA
mov [si+4],bx
mov bx,es
mov [si+6],bx
mov [si+8],eax
.loop2:
push bp ; Sectors left
cmp bp,[MaxTransfer]
jbe .bp_ok
mov bp,[MaxTransfer]
.bp_ok:
mov [si+2],bp
push si
mov dl,[DriveNo]
mov ah,42h ; Extended Read
call xint13
pop si
pop bp
movzx eax,word [si+2] ; Sectors we read
add [si+8],eax ; Advance sector pointer
sub bp,ax ; Sectors left
shl ax,SECTORSIZE_LG2-4 ; 2048-byte sectors -> segment
add [si+6],ax ; Advance buffer pointer
and bp,bp
jnz .loop2
mov eax,[si+8] ; Next sector
ret
; INT 13h with retry
xint13:
mov byte [RetryCount], retry_count
.try:
pushad
int 13h
jc .error
add sp, byte 8*4 ; Clean up stack
ret
.error:
mov [DiskError], ah ; Save error code
popad
dec byte [RetryCount]
jz .real_error
push ax
mov al,[RetryCount]
mov ah,[dapa+2] ; Sector transfer count
cmp al,2 ; Only 2 attempts left
ja .nodanger
mov ah,1 ; Drop transfer size to 1
jmp short .setsize
.nodanger:
cmp al,retry_count-2
ja .again ; First time, just try again
shr ah,1 ; Otherwise, try to reduce
adc ah,0 ; the max transfer size, but not to 0
.setsize:
mov [MaxTransfer],ah
mov [dapa+2],ah
.again:
pop ax
jmp .try
.real_error:
mov si, diskerr_msg
call writemsg
mov al, [DiskError]
call writehex2
mov si, ondrive_str
call writestr
mov al, dl
call writehex2
call crlf
; Fall through to kaboom
;
; kaboom: write a message and bail out. Wait for a user keypress,
; then do a hard reboot.
;
kaboom:
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
sti
mov si, err_bootfailed
call writestr
call getchar
cli
mov word [BIOS_magic], 0 ; Cold reboot
jmp 0F000h:0FFF0h ; Reset vector address
getchar:
.again:
mov ah, 1 ; Poll keyboard
int 16h
jz .again
.kbd:
xor ax, ax ; Get keyboard input
int 16h
.func_key:
ret
;
; pollchar: check if we have an input character pending (ZF = 0)
;
pollchar:
pushad
mov ah,1 ; Poll keyboard
int 16h
popad
ret
isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0
copyright_str db ' Copyright (C) 1994-2002 H. Peter Anvin', CR, LF, 0
presskey_msg db 'Press any key to boot from CD', 0
dot_msg db '.',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
rootloc_msg: db 'Root directory location: ', 0
rootlen_msg: db 'Root directory length: ', 0
rootsect_msg: db 'Root directory length(sectors): ', 0
fileloc_msg: db 'SETUPLDR.SYS location: ', 0
filelen_msg: db 'SETUPLDR.SYS length: ', 0
filesect_msg: db 'SETUPLDR.SYS length(sectors): ', 0
findfail_msg: db 'Failed to find file!', 0
startldr_msg: db 'Starting SETUPLDR.SYS', 0
%endif
nosecsize_msg: db 'Failed to get sector size, assuming 0800', 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
nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF, 0
isolinux_str db 'IsoBoot: ', 0
crlf_msg db CR, LF, 0
diskerr_msg: db 'Disk error ', 0
ondrive_str: db ', drive ', 0
err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
isolinux_dir db '\LOADER', 0
no_dir_msg db 'Could not find the LOADER directory.', CR, LF, 0
isolinux_bin db 'SETUPLDR.SYS', 0
no_isolinux_msg db 'Could not find SETUPLDR.SYS.', CR, LF, 0
;
; El Torito spec packet
;
align 8, db 0
spec_packet: db 13h ; Size of packet
sp_media: db 0 ; Media type
sp_drive: db 0 ; Drive number
sp_controller: db 0 ; Controller index
sp_lba: dd 0 ; LBA for emulated disk image
sp_devspec: dw 0 ; IDE/SCSI information
sp_buffer: dw 0 ; User-provided buffer
sp_loadseg: dw 0 ; Load segment
sp_sectors: dw 0 ; Sector count
sp_chs: db 0,0,0 ; Simulated CHS geometry
sp_dummy: db 0 ; Scratch, safe to overwrite
;
; EBIOS drive parameter packet
;
align 8, db 0
drive_params: dw 30 ; Buffer size
dp_flags: dw 0 ; Information flags
dp_cyl: dd 0 ; Physical cylinders
dp_head: dd 0 ; Physical heads
dp_sec: dd 0 ; Physical sectors/track
dp_totalsec: dd 0,0 ; Total sectors
dp_secsize: dw 0 ; Bytes per sector
dp_dpte: dd 0 ; Device Parameter Table
dp_dpi_key: dw 0 ; 0BEDDh if rest valid
dp_dpi_len: db 0 ; DPI len
db 0
dw 0
dp_bus: times 4 db 0 ; Host bus type
dp_interface: times 8 db 0 ; Interface type
db_i_path: dd 0,0 ; Interface path
db_d_path: dd 0,0 ; Device path
db 0
db_dpi_csum: db 0 ; Checksum for DPI info
;
; EBIOS disk address packet
;
align 8, db 0
dapa: dw 16 ; Packet size
.count: dw 0 ; Block count
.off: dw 0 ; Offset of buffer
.seg: dw 0 ; Segment of buffer
.lba: dd 0 ; LBA (LSW)
dd 0 ; LBA (MSW)
alignb 4, db 0
MaxTransfer dw 2 ;32 ; Max sectors per transfer
times 2046-($-$$) db 0 ; Pad to file offset 2046
dw 0aa55h ; BootSector signature
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -