# boot.S86 - boot sector for DOS ramdisk # # Copyright (C) 1996-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: boot.S86,v 1.1 2003/03/09 00:43:09 gkminix Exp $ # #==================================================================== # #include "common.i86" #include "boot.i86" .file "boot.s86" .line 31 # #==================================================================== # # Define the text segment. This segment has to start at 0x7C00, # but we cant use the .org directive. The assembler would then # write 0x7C00 times 0 values. Instead we have to tell the linker # using a ldscript file that this starts at an absolute address. # \(.text) .global _start _start: jmp start nop # Define boot record (defaults are for 1.44MB floppy disk) .ascii "MSDOS5.0" # OEM name bpb: bpsect: .word SECT_SIZE # bytes per sector spc: .byte BOOT_SPC # number of sectors per cluster resvd: .word 1 # number of reserved sectors fatnum: .byte 2 # number of FATs dirnum: .word BOOT_DIRNUM # number of entries in root directory .word BOOT_SECNUM # total number of sectors on disk fmtid: .byte BOOT_FORMAT # media ID spfat: .word BOOT_SPFAT # sectors per fat sptrk: .word BOOT_SPTRK # sectors per track hdnum: .word 2 # number of heads hidden: .long 0 # number of hidden sectors .long BOOT_SECNUM # total number of sectors on disk bootid: .byte BOOT_ID # BIOS number of boot device .byte 0 # head number of boot sector .byte 0x29 # disk attributes .long 0 # volume number .ascii "NO NAME " # volume name .ascii "FAT12 " # filesystem name ldnum: .word 4 # min no of sectors in IO.SYS ldofs: .word IOSYS_SEG * 16 # load offset for IO.SYS # Start of main routine. First we have to check if we have to relocate # ourselves in case we have to load so many IO.SYS sectors that we are # going to overwrite anything. start: mov bx,cs mov ds,bx mov [runseg],bx # save run segment mov si,offset _start mov cx,[bpsect] mov ax,[ldnum] # compute size of IO.SYS in bytes inc ax mul cx add ax,[ldofs] # add to load offset adc dx,0 jnz start1 cmp ax,si # should not exceed start address jbe start3 start1: sub ax,si sbb dx,0 shr ax,4 shl dx,12 # compute start segment number of or ax,dx # this boot sector add bx,ax mov es,bx mov di,si cld rep movsb # move boot sector push bx mov ax,offset start3 # jump to new copy push ax lret start3: cli mov cx,cs mov ss,cx mov sp,offset _start - 4 # set stack to beginning of code sti # Get DPB vector and initialize disk system. The disk parameter block vector # is only required by DOS. mov ax,0x9C05 int 0xF8 # get DPB address from ramdisk driver xor ax,ax mov ds,ax mov si,DPB_VECT push dword ptr [si] # push old DPB address push ax # push address of interrupt vector push si mov word ptr [si + 0],dx # set new DPB address mov word ptr [si + 2],bx mov ds,cx mov es,cx xor dx,dx int 0x13 # initialize disk system jc doerr # Compute the logical number of the first sector of the data area. We # assume that IO.SYS is always located at the beginning. This might # not be true for a real DOS disk, but is always correct for a disk # image produced by mknbi. mov al,[fatnum] xor ah,ah mul word ptr [spfat] # compute size of FAT add ax,word ptr [hidden+0] adc dx,word ptr [hidden+2] # add number of hidden sectors add ax,[resvd] adc dx,0 # add number of reserved sectors mov bx,DIR_SEG add bx,[runseg] mov word ptr [ldseg],bx call rdsect # read first directory sector jc doerr push dx mov cx,ax mov ax,32 mul word ptr [dirnum] # compute size of root directory mov bx,[bpsect] # area add ax,bx # round up to sector size dec ax div bx add ax,cx # add number of sectors used by pop dx # root directory adc dx,0 # Now load the first 4 sectors of IO.SYS at 0x0070. Note that starting # with Windows 95b (aka OSR2), Microsoft changed the format of IO.SYS # from a plain binary executable into a sort of EXE-style file. If the # EXE-file header can be found at the beginning of IO.SYS, we have to # call it at offset 0x0200, otherwise at offset 0x0000. push dx push ax mov bx,[ldofs] shr bx,4 # compute load segment add bx,[runseg] mov [ldseg],bx mov [runseg],bx mov cx,[ldnum] start7: call rdsect # read sector jc doerr add ax,1 adc dx,0 # continue with next sector mov bx,[bpsect] shr bx,4 add [ldseg],bx loop start7 pop bx # remember first sector of IO.SYS pop ax mov cx,[runseg] mov es,cx cmp word ptr es:[0],EXE_SIG jne start8 # set IO.SYS execution address mov word ptr [jmpadr],0x0200 start8: mov ch,[fmtid] # prepare registers for IO.SYS mov dl,[bootid] mov bp,offset _start mov word ptr [bp - 2],ax mov word ptr [bp - 4],bx cmp word ptr [ldofs],FREEDOS_SEG * 16 jne start9 # Arghhh... FreeDOS expects the boot mov bl,dl # drive in BL, not DL as all others start9: mov si,offset bpb mov di,2 # set first cluster no. of IO.SYS ljmp [jmpadr] # call IO.SYS # #==================================================================== # # Print error message and terminate # Input: none # Output: Routine does not return # Changed registers: All # doerr: mov si,offset errmsg doerr2: lodsb or al,al jz doerr3 mov ah,0x0E mov bx,7 # print using BIOS int 0x10 jmp doerr2 doerr3: xor ax,ax int 0x16 # wait for key press pop si # get pointer to int 0x1E vector pop ds pop word ptr [si] # restore old DPB address pop word ptr [si + 2] int 0x19 # reboot the system # #==================================================================== # # Read one logical sector from the ram disk # Input: DX:AX - 32-bit logical sector number # Output: none # Changed registers: none # rdsect: push ax push bx push dx push cx div word ptr [sptrk] inc dl mov cl,dl xor dx,dx div word ptr [hdnum] # convert logical sector number into mov dh,dl # cylinder/head/sector format mov ch,al ror ah,2 or cl,ah mov ax,0x0201 mov dl,[bootid] push es mov es,[ldseg] # set load address xor bx,bx int 0x13 # read one sector from ramdisk pop es pop cx pop dx pop bx pop ax ret # #==================================================================== # # Data area # errmsg: .byte 0x0D, 0x0A .ascii "Ramdisk error - hit a key" .byte 0x0D, 0x0A .byte 0 # This "magic" word needs to be here for MS-DOS 7.1 compatibility \(.org) 0x01EE .word 0x017F # Some misc. variables jmpadr: .word 0 # address of IO.SYS to jump to runseg: .word 0 # run segment ldseg: .word 0 # load segment # The end of the boot sectors has to contain the boot signature. \(.org) BOOT_SIG_OFS - BOOT_OFFSET .word BOOT_SIG_PRIV # #==================================================================== # .end