; -*- fundamental -*- (asm-mode sucks)
; $Id: syslinux.asm,v 1.10 1998/05/07 07:03:17 hpa Exp $
; -----------------------------------------------------------------------
;
; Copyright 1998 H. Peter Anvin - All Rights Reserved
;
; 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.
;
; -----------------------------------------------------------------------
section .text
org 0100h
_start:
mov ax,3000h ; Get DOS version
int 21h
xchg al,ah
mov [DOSVersion],ax
cmp ax,0314h ; DOS 3.20 minimum
jae dosver_ok
mov dx,msg_ancient_err
jmp die
section .bss
alignb 2
DOSVersion: resw 1
section .text
;
; Scan command line for a drive letter followed by a colon
;
dosver_ok:
xor cx,cx
mov si,pspCommandArg
mov cl,[pspCommandLen]
cmdscan1: jcxz bad_usage ; End of command line?
lodsb ; Load character
dec cx
cmp al,' ' ; White space
jbe cmdscan1
cmp al,'-'
je scan_option
or al,020h ; -> lower case
cmp al,'a' ; Check for letter
jb bad_usage
cmp al,'z'
ja bad_usage
sub al,'a' ; Convert to zero-based index
mov [DriveNo],al ; Save away drive index
section .bss
DriveNo: resb 1
section .text
;
; Got the leading letter, now the next character must be a colon
;
got_letter: jcxz bad_usage
lodsb
dec cx
cmp al,':'
jne bad_usage
;
; Got the colon; the rest better be whitespace
;
got_colon: jcxz got_cmdline
lodsb
dec cx
cmp al,' '
jbe got_colon
;
; We end up here if the command line doesn't parse
;
bad_usage: mov dx,msg_unfair
jmp die
section .text
;
; Scan for options after a - sign. The only recognized option right now
; is -s.
;
scan_option: jcxz bad_usage
lodsb
dec cx
cmp al,' '
jbe cmdscan1
or al,20h
cmp al,'s'
jne bad_usage
push si ; make_stupid doesn't save these
push cx
call make_stupid ; Enable stupid boot sector
pop cx
pop si
jmp short scan_option
got_cmdline:
mov dl,[DriveNo]
inc dl ; 1-based
mov bx,DPB
mov ah,32h
int 21h ; Get Drive Parameter Block
and al,al
jnz filesystem_error
cmp word [bx+dpbSectorSize],512 ; Sector size = 512 required
jne sectorsize_error
cmp byte [bx+dpbClusterShift],5 ; Max size = 16K = 2^5 sectors
jna read_bootsect
hugeclust_error:
mov dx,msg_hugeclust_err
jmp die
filesystem_error:
mov dx,msg_filesystem_err
jmp die
sectorsize_error:
mov dx,msg_sectorsize_err
jmp die
;
; Good enough. Now read the old boot sector and copy the superblock.
;
section .data
align 4, db 0
DISKIO equ $
diStartSector: dd 0 ; Absolute sector 0
diSectors: dw 1 ; One sector
diBuffer: dw SectorBuffer ; Buffer offset
dw 0 ; Buffer segment
cmp word [DOSVersion],0400h ; DOS 4.00 has a new interface
jae .new
old:
mov bx,SectorBuffer
mov cx,1 ; One sector
jmp short .common
new:
mov bx,DISKIO
mov [bx+8],ax ; Buffer segment
mov cx,-1
common:
xor dx,dx ; Absolute sector 0
mov al,[DriveNo]
int 25h ; DOS absolute disk read
pop ax ; Remove flags from stack
jc disk_read_error
mov si,SectorBuffer+11 ; Offset of superblock
mov di,BootSector+11
mov cx,51 ; Superblock = 51 bytes
rep movsb ; Copy the superblock
jmp short write_file
disk_read_error:
mov dx,msg_read_err
jmp die
;
; Writing LDLINUX.SYS
;
write_file:
; 0. Set the correct filename
mov al,[DriveNo]
add [ldlinux_sys_str],al
; 1. If the file exists, strip its attributes and delete
xor cx,cx ; Clear attributes
mov dx,ldlinux_sys_str
mov ax,4301h ; Set file attributes
int 21h
mov dx,ldlinux_sys_str
mov ah,41h ; Delete file
int 21h
section .data
ldlinux_sys_str: db 'A:\LDLINUX.SYS', 0
section .text
; 2. Create LDLINUX.SYS and write data to it
mov dx,ldlinux_sys_str
xor cx,cx ; Normal file
mov ah,3Ch ; Create file
int 21h
jc file_write_error
mov [FileHandle],ax
mov bx,ax
mov cx,ldlinux_size
mov dx,LDLinuxSYS
mov ah,40h ; Write data
int 21h
jc file_write_error
cmp ax,ldlinux_size
jne file_write_error
mov bx,[FileHandle]
mov ah,3Eh ; Close file
int 21h
section .bss
FileHandle: resw 1
section .text
; 3. Set the readonly flag on LDLINUX.SYS
mov dx,ldlinux_sys_str
mov cx,1 ; Read only
mov ax,4301h ; Set attributes
int 21h
;
; Writing boot sector
;
write_bootsect:
cmp word [DOSVersion],0400h ; DOS 4.00 has a new interface
jae .new
old:
mov bx,BootSector
mov cx,1 ; One sector
jmp short .common
new:
mov bx,DISKIO
mov word [bx+6],BootSector
mov cx,-1
common:
xor dx,dx ; Absolute sector 0
mov al,[DriveNo]
int 26h ; DOS absolute disk write
pop ax ; Remove flags from stack
jc disk_write_error
all_done: mov ax,4C00h ; Exit good status
int 21h
;
; Error routine jump
;
disk_write_error:
file_write_error:
mov dx,msg_write_err
die:
push cs
pop ds
push dx
mov dx,msg_error
mov ah,09h
int 21h
pop dx
mov ah,09h ; Write string
int 21h
mov ax,4C01h ; Exit error status
int 21h
;
; This includes a small subroutine make_stupid to patch up the boot sector
; in case we give the -s (stupid) option
;
%include "stupid.inc"
section .data
msg_error: db 'ERROR: $'
msg_ancient_err: db 'DOS version 3.20 or later required', 0Dh, 0Ah, '$'
msg_filesystem_err: db 'Filesystem not found on disk', 0Dh, 0Ah, '$'
msg_sectorsize_err: db 'Sector sizes other than 512 bytes not supported', 0Dh, 0Ah, '$'
msg_hugeclust_err: db 'Clusters larger than 16K not supported', 0Dh, 0Ah, '$'
msg_read_err: db 'Boot sector read failed', 0Dh, 0Ah, '$'
msg_write_err: db 'Disk write failed', 0Dh, 0Ah, '$'