; loader.asm ; ; originally written on Fri 05-27-1994 by Ed Beroset ; ; rewritten on Sun 11-25-2001 by Ed Beroset ; CalcClust2 PROTO C cResSectors:WORD, cFATsecs:WORD, cFATs:BYTE LsectToGeom PROTO C lHiddenSecs:DWORD, \ lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD FindFile PROTO C dirbuffer:WORD, limit:WORD, filespec:WORD public BootFileName PartEntry STRUC Bootable db ? ;80h = bootable, 00h = nonbootable BeginHead db ? ;beginning head BeginSector db ? ;beginning sector BeginCylinder db ? ;beginning cylinder FileSystem db ? ;name of file system EndHead db ? ;ending head EndSector db ? ;ending sector EndCylinder db ? ;ending cylinder StartSector dd ? ;starting sector (relative to beg. of disk) PartSectors dd ? ;number of sectors in partition PartEntry ENDS BootSector STRUC bsJump db 0EBh, 03eh, 090h ;(bsExtra - bsJump), 090h ; E9 XX XX or EB xx 90 OemName db 8 dup (?) ; OEM name and version ; start of BIOS parameter block BytesPerSec dw ? ; bytes per sector SecPerClust db ? ; sectors per cluster ResSectors dw ? ; number of reserved sectors FATs db ? ; number of FATs RootDirEnts dw ? ; number of root directory entries Sectors dw ? ; total number of sectors (see HugeSectors) Media db ? ; media descriptor byte (0f0h for floppies) FATsecs dw ? ; number of sectors per FAT SecPerTrack dw ? ; sectors per track Heads dw ? ; number of heads HiddenSecs dd ? ; number of hidden sectors HugeSectors dd ? ; number of sectors if Sectors equals 0 ; end of BIOS parameter block DriveNumber db ? ; Reserved1 db ? ; BootSignature db ? ; VolumeID dd ? ; VolumeLabel db 11 dup (?) FileSysType db 8 dup (?) bsExtra dw ? BootSector ENDS DirEntry STRUC FileName db '????????' ;name Extension db '???' ;extension Attributes db ? ;attributes Reserved db 10 dup (?) ;reserved Time dw ? ;time stamp Date dw ? ;date stamp StartCluster dw ? ;starting cluster FileSize dd ? ;file size DirEntry ENDS CR EQU 0DH LF EQU 0AH yonder segment para use16 at 2000h org 0h destination proc far destination endp yonder ends myfilename = offset BootFileName code segment para public use16 '_CODE' .386 assume cs:code, ds:code, es:code, ss:code org 7c00h main PROC MBR: Boot bootsector < ,'BEROSET ',512,1,1,2,224,2880,0f0h,9,18,2,\ 0,0,0,0,29h,02a04063ch,'BEROSET 001',\ 'FAT12 ',07df1h> over: mov ax,cs ; cli mov ss,ax ; point ss:sp to CS:7c00h mov sp,7c00h ; which sets up a stack in first 64K sti mov ds,ax mov es,ax ;**************************************************************************** ; ; CalcClustOff - calculates the starting logical sector number of ; cluster 0, which isn't really a cluster, but the ; number returned is useful for calculations converting ; cluster number to logical sector ; ; INPUT: ResSectors, FATsecs, FATs ; OUTPUT: dx:ax contains the starting logical sector number ; DESTROYED: none ; ;**************************************************************************** CalcClustOff PROC xor dh,dh mov ax,[Boot.FatSecs] mov dl,[Boot.FATs] mul dx add ax,[Boot.ResSectors] adc dx,0 ; now dx:ax = FATs * FATsecs + ResSectors mov word ptr [ClustOffs],ax mov word ptr [ClustOffs+2],dx mov dx,20h ; bytes per dir entry mov ax,[Boot.RootDirEnts] mul dx ; multiply 'em out div word ptr [Boot.BytesPerSec] ; and divide by bytes/sec add word ptr [ClustOffs],ax adc word ptr [ClustOffs+2],dx ; create the aggregate mov al,[Boot.SecPerClust] ; xor ah,ah ; shl ax,1 ; AX = SecPerClust * 2 sub word ptr [ClustOffs],ax ; sbb word ptr [ClustOffs+2],0 ; propagate carry flag ; mov ax,word ptr [ClustOffs] ; ; mov dx,word ptr [ClustOffs+2] ; ; ret CalcClustOff ENDP ; mov WORD ptr [ClustOffs],ax ; mov WORD ptr [ClustOffs+2],dx mov bx,offset Boot invoke CalcClust2 , \ WORD ptr (BootSector PTR [bx]).ResSectors, \ WORD ptr (BootSector PTR [bx]).FATsecs, \ BYTE ptr (BootSector PTR [bx]).FATs ; now dx:ax contains the logical sector for cluster 2 invoke LsectToGeom , \ WORD ptr (BootSector PTR [bx]).HiddenSecs , \ WORD ptr ((BootSector PTR [bx]).HiddenSecs+2),\ (BootSector PTR [bx]).Heads, \ (BootSector PTR [bx]).SecPerTrack mov dl,(BootSector PTR [bx]).DriveNumber mov bx,offset buff retry1: mov al,(BootSector PTR [MBR]).SecPerClust mov ah,2h ; get ready to read int 13h jc retry1 ; now find our desired filename within buffer (which has the root dir) invoke FindFile, \ bx, 200h * 40h, 07d80h xor dh,dh mov dl,(BootSector PTR [MBR]).SecPerClust mov si,ax mov ax,(DirEntry PTR [si]).StartCluster mul dx add ax,WORD ptr [ClustOffs] adc dx,WORD ptr [ClustOffs+2] ; now dx:ax contains logical sector number for start of file invoke LsectToGeom, \ WORD ptr (BootSector PTR [MBR]).HiddenSecs , \ WORD ptr ((BootSector PTR [MBR]).HiddenSecs)+2,\ (BootSector PTR [MBR]).Heads, \ (BootSector PTR [MBR]).SecPerTrack retry2: mov si,offset Boot mov dl,(BootSector PTR [si]).DriveNumber mov ah,2h ; read in a cluster's worth of data mov al,(BootSector PTR [si]).SecPerClust ; point to our magic location mov bx,seg destination mov es,bx mov bx,offset destination int 13h jc retry2 @@exit: jmp destination main ENDP ;**************************************************************************** ; ; LsectToGeom - converts from logical sector number to the physical ; geometry (head, cylinder, track) in the form required ; by the BIOS (Int 13h) disk read and write calls. ; ; INPUT: dx:ax=lsect, HiddenSecs, Heads, SecPerTrack ; OUTPUT: cx, dx are set with cylinder/track, and head respectively ; DESTROYED: none ;**************************************************************************** LsectToGeom PROC C USES ax, ;save registers we'll use lHiddenSecs:DWORD, \ lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD stc ;add one additional adc ax, WORD ptr [lHiddenSecs] ;add starting sector adc dx, WORD ptr [lHiddenSecs+2] ; div [lSecPerTrack] ; mov cl,dl ;store sector in cl xor dx,dx ; div [lHeads] ; mov dh,dl ;store head in dh mov ch,al ;store low 8 bits of cylinder in ch shr ax,1 ; shr ax,1 ; and al,0c0h ;pass through two hi bits only or cl,ah ;mov bits into location ret ; LsectToGeom ENDP ;**************************************************************************** ; ; CalcClust2 - calculates the starting logical sector number of ; cluster 2, (the beginning of data space for ; partitions). ; ; INPUT: ResSectors, FATsecs, FATs ; OUTPUT: dx:ax contains the starting logical sector number ; DESTROYED: none ; ;**************************************************************************** CalcClust2 PROC C cResSectors:WORD, cFATsecs:WORD, cFATs:BYTE xor dx,dx ; mov ax,[cFATsecs] ; mul [cFATs] ; add ax,[cResSectors] ; adc dx,0 ; ret CalcClust2 ENDP ;**************************************************************************** ; ; FindFile - given a memory buffer containing the directory data ; and a static file name for which to search, this routine ; finds the file and returns a pointer to its directory ; entry in ds:si ; ; INPUT: dirbuffer, filespec ; OUTPUT: ax contains pointer to directory entry (or NULL) ; DESTROYED: none ;**************************************************************************** FindFile PROC C USES cx dx di si es, dirbuffer:WORD, limit:WORD, filespec:WORD mov cx,ds ; mov es,cx ; es and ds point to same segment cld ; always count forward mov ax,[dirbuffer] ; load 'em up add [limit],ax mov dx,[filespec] ; keepsearching: mov cx,11 ; size of dos filename (8.3) mov si,dx ; mov di,ax ; repe cmpsb ; compare 'em jz foundit ; add ax,20h ; size of directory entry cmp ax,[limit] jb keepsearching xor ax,ax foundit: ret FindFile ENDP BootFileName db "BEROSET SYS" ;the boot loader for this OS ; MBR db 0200h DUP (?) buff db 0200h * 40h DUP (?) ClustOffs dd ? org 7dfeh dw 0AA55h ; signature byte code ends END main