!************************************************************************** !* !* Program to check for an installed bootrom -- floppy loader !* !* Module: loader.S !* Purpose: Load romcheck program from floppy !* Entries: called by BIOS at offset 0 !* !************************************************************************** !* !* Copyright (C) 1998-2003 Gero Kuhlmann !* !* 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; either version 2 of the License, or !* any later version. !* !* This program is distributed in the hope that it will be useful, !* but WITHOUT ANY WARRANTY; without even the implied warranty of !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !* GNU General Public License for more details. !* !* You should have received a copy of the GNU General Public License !* along with this program; if not, write to the Free Software !* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: loader.S,v 1.4 2003/01/25 23:29:43 gkminix Exp $ !* ! !************************************************************************** ! ! Equates for the floppy loader: ! BOOTSEG equ $FFFF ! segment of cold boot vector STACKTOP equ $FFFE ! top of stack in code segment SECTSIZE equ 512 ! size of one floppy sector SECTNUM equ 64 ! number of sectors to load (32kB) DPTVECTOR equ $0078 ! address of pointer to DPT DPTSIZE equ 13 ! size of DPT DPTSPTOFS equ $04 ! offset to sectors per track in DPT ! !************************************************************************** ! ! The loader works by first patching the floppy disk parameter table, ! and then trying to read the last sector of the floppy in order to ! find out about the disk size. Then it will load the remaining romcheck ! program from the diskette. .text ! begin loader text segment entry start org 0 start: cli call dobot1 dobot1: pop ax ! determine the offset sub ax,#dobot1 mov cl,#4 mov bx,cs mov dx,bx ! convert the base address from and dx,#$F000 ! seg:ofs format into sort of a shl bx,cl ! linear address. this conversion add bx,ax ! assumes that no overflow can occur. ! compute a code segment address shr bx,cl ! which lets this code start at add bx,dx ! offset 0. this is necessary so push bx ! all offsets computed by as86 work. mov ax,#dobot2 push ax retf ! this will jump to dobot2 with new ! code segment register dobot2: mov ax,cs mov ds,ax ! load segment registers mov es,ax mov ss,ax mov sp,#STACKTOP ! finally set the stack sti ! Now determine the number of sectors per track on the floppy. To do ! this the disk parameter table has first to be changed, so that the ! BIOS is able to access at least 18 sectors in a track. cld push ds mov dx,ds xor ax,ax mov es,ax ! first save the old disk parameter seg es ! table lds si,(DPTVECTOR) mov es,dx seg es mov word ptr (oldvect+0),si ! save old vector seg es mov word ptr (oldvect+2),ds mov di,#newdpt mov cx,#DPTSIZE rep movsb pop ds mov al,#18 mov (newdpt + DPTSPTOFS),al ! set new number of sectors per track xor ax,ax ! set pointer to new DPT mov es,ax seg es mov word ptr (DPTVECTOR + 0),#newdpt seg es mov word ptr (DPTVECTOR + 2),ds ! Next try to find the number of sectors per track. To do this, the ! last sector for each disk format is read. This idea has been taken ! from the Linux boot sector. xor ah,ah ! reset drive 0 xor dl,dl int $13 mov ax,ds mov es,ax ! set load address to end of loader mov bx,#flopend xor dx,dx mov cx,#1 ! load one sector to initialize drive mov ax,#$0201 int $13 xor dx, dx ! drive 0, head 0 mov cx,#18 ! sector 18, track 0 mov ax,#$0201 ! read one sector int $13 jnc gotit mov cx,#15 ! sector 15 mov ax,#$0201 ! read one sector int $13 jnc gotit mov cx,#9 gotit: mov sects,cx ! save number of sector per track ! Now load the romcheck program starting at the second sector of track 0 ! directly at the end of this floppy loader. We blindly load 32kB in the ! hope that romcheck is not larger than this. mov bx,#flopend ! starting offset mov dx,#SECTNUM ! number of sectors mov ax,#1 ! starting sector rdloop: or dx,dx jz loaded push ax push dx call cvtsec ! compute sector information mov ax,#$0201 ! load one sector int $13 pop dx pop ax jc lderr dec dx ! decrement sector count inc ax ! increment sector number add bx,#SECTSIZE ! increment load pointer jmp rdloop lderr: mov si,#dskmsg ! print error message call prnstr jmp reboot ! Restore the old DPT vector and call the romcheck program loaded: cld push ds les si,oldvect xor ax,ax ! restore old vector mov ds,ax mov word ptr (DPTVECTOR + 0),si mov word ptr (DPTVECTOR + 2),es pop ds xor ax,ax xor dx,dx ! reset disk system int $13 mov ax,cs add ax,#flopend / 16 ! compute the start address so that mov ds,ax ! its offset is zero mov es,ax cli mov ss,ax mov sp,#STACKTOP ! set the stack sti push ax xor ax,ax push ax retf ! call romcheck program ! !************************************************************************** ! ! Reboot the system ! Input: None ! Output: Routine does not return ! Registers changed: All ! reboot: mov si,#botmsg call prnstr xor ah,ah ! wait for a key press int $16 mov ax,#$0040 mov ds,ax mov word ptr ($0072),#$1234 ! indicates warm boot jmpi 0,BOOTSEG ! reboot the system ! !************************************************************************** ! ! Routine to convert an absolute sector into a sector/track/head information. ! Input: AX - absolute sector number ! Output: CL - sector number ! CH - track number ! DH - head number ! DL - 0 (number for drive 0) ! Registers changed: AX, CX, DX ! cvtsec: xor dx,dx div word ptr (sects) ! compute sector number in a track inc dl ! sector numbers always start with 1 mov cl,dl mov dx,ax shr ax,#1 ! divide by number of heads mov ch,al ! save track number and dx,#1 ! mask head number xchg dl,dh ret ! !************************************************************************** ! ! Routine to print a string onto the console. ! Input: DS:SI - address of NULL terminated string ! Output: None ! Registers changed: AX, SI ! prnstr: push bx mov bx,#$0007 ! set color and screen page prnst1: lodsb ! loop over all characters or al,al jz prnst9 mov ah,#$0E ! BIOS command for character output int $10 ! send character to screen jmp prnst1 prnst9: pop bx ret ! !************************************************************************** ! ! Strings and messages: ! dskmsg: .ascii 'romcheck: Error reading diskette' .byte $0D,$0A,0 botmsg: .ascii 'Press any key to reboot...' .byte 0 ! !************************************************************************** ! ! Data space for the floppy loader: ! sects: .word 0 ! number of sectors per track oldvect: .long 0 ! old dpt vector newdpt: .space DPTSIZE ! changed disk parameter table .org SECTSIZE - 2 .word $AA55 flopend: ! end of floppy loader sector ! !************************************************************************** ! end