;=-------------------------------------------------------------------------= ; ; MZ Loader 2.0 FAT32 Boot Sector ; ; Copyright (c) 1999-2000 by Thomas Kjoernes, all rights reserved. ; ; ; Boot Sector Overview: ; --------------------- ; ; - Support for multiple boot images. You can add more images ; between the szImageListDef/End labes. The first image found ; in the root directory will be loaded. ; ; - Support for fully searching the Root Directory through out ; its cluster chain for the image files. ; ; - Support for "MZ" executables as well as plain binaries. ; ; ; Known limitations: ; ------------------ ; ; - Does not support systems without INT13 extensions. ; - Does not provide any error messages; calls INT18 on any errors. ; ; ; Memory Map: ; ----------- ; ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ; ³ Interrupt Vector Table ³ 0000 ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ BIOS Data Area ³ 0040 ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ PrtScr Status / Unused ³ 0050 ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ Image Load Address ³ 0060 ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ Available Memory ³ nnnn ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ 2KB Boot Stack ³ A000 - SizeOf(BootSector) - 2KB ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; ³ Boot Sector ³ A000 - SizeOf(BootSector) ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ; A000 ; ; ; Boot Image Startup (register values): ; ------------------------------------- ; ; ds = load segment, this is where the executable is loaded. ; es = free segment, very first available paragraph above image. ; ss = this is the stack segment somewhere near top of memory. ; ; dl = boot drive number ; ; dh = ??? (undoc) ; cx = ??? (undoc) ; si = ??? (undoc) ; di = ??? (undoc) ; ; ax:bx = CS:IP used to RETF to the image. ; ; ss:sp = pointer to 2KB stack. ; ss:bp = pointer to boot sector, with STD_VARS located below it. ; ; The STD_VARS structure includes the relative LBA address of the ; disk data area and the image load and FAT segment addresses. ; ;=-------------------------------------------------------------------------= .386p INCLUDE fat.inc codeSegment SEGMENT USE16 'boot' ASSUME cs:codeSegment, ds:codeSegment, ss:codeSegment FAT32_BOOT <"MZLDR2.0"> ;=----------------------------------------------------------= ; Detect memory, setup stack, buffers and relocate ourself ;=----------------------------------------------------------= int 12h ; get conventional memory size shl ax, 6 ; and convert it to paragraphs sub ax, 512 / 16 ; es = ax - 512 mov es, ax ; ; setup stack and base pointers sub ax, 2048 / 16 ; ss = ax - 2KB mov ss, ax ; mov sp, 2048 ; 2KB stack mov bp, sp ; mov ax, 0060h ; ax = "load" segment ; copy ourself to top of memory mov cx, 256 mov si, 7C00h xor di, di rep movs WORD PTR es:[di], cs:[si] ; jump to relocated code push es push OFFSET mainEntryPoint retf mainEntryPoint: mov BS.bs32DriveNumber, dl mov es, ax ; es = "load" segment ; calculate sector buffer address mov ax, BPB.bpbBytesPerSector shr ax, 4 mov di, ss sub di, ax ;=----------------------------------------------------------= ; Calculate start of Data Area and push STD_VARS ;=----------------------------------------------------------= mov cl, BPB.bpbNumberOfFATs mov ax, WORD PTR BPB.bpb32SectorsPerFAT[2] mul cx xchg ax, si mov ax, WORD PTR BPB.bpb32SectorsPerFAT[0] mul cx add ax, BPB.bpbReservedSectors adc dx, si push dx ; stdDataAreaHi push ax ; stdDataAreaLo push di ; stdFATSegment push es ; stdBufSegment ;=----------------------------------------------------------= ; Search through the Root Directory for an image file ;=----------------------------------------------------------= mov esi, BPB.bpb32RootCluster fat32FindFileMain: call fat32ReadCluster shr ebx, 5 push si mov cl, 11 xor di, di fat32FindFileMore: mov si, OFFSET szImageListDef fat32FindFileNext: pusha rep cmps BYTE PTR cs:[si], es:[di] popa je fat32FindFileDone add si, cx cmp si, OFFSET szImageListEnd jb fat32FindFileNext add di, 32 dec bx jnz fat32FindFileMore pop si cmp esi, 0FFFFFF8h jb fat32FindFileMain int 18h fat32FindFileDone: pop si ;=----------------------------------------------------------= ; Load entire boot image file into memory ;=----------------------------------------------------------= push es:[di].dirClusterHigh push es:[di].dirCluster pop esi fat32LoadFileMain: call fat32ReadCluster jc fat32LoadFileDone shr ebx, 4 ; ebx = paragraphs read mov ax, es ; add ax, bx ; es = new buffer segment mov es, ax ; jmp fat32LoadFileMain fat32LoadFileDone: ;=----------------------------------------------------------= ; Do some special checks on the image and transfer control ;=----------------------------------------------------------= mov ax, VAR.stdBufSegment mov ds, ax xor bx, bx xor si, si ; check for "MZ" executable signature cmp WORD PTR ds:[si], "ZM" jne bootExecFile add ax, ds:[si][08h] ; ax = image base mov cx, ds:[si][06h] ; cx = reloc items mov bx, ds:[si][18h] ; bx = reloc table pointer jcxz bootHackDone bootHackFile: mov di, ds:[bx][0] ; di = item ofs mov dx, ds:[bx][2] ; dx = item seg (rel) add dx, ax ; dx = item seg (abs) push ds ; mov ds, dx ; ds = dx add ds:[di], ax ; fixup pop ds ; add bx, 4 ; point to next entry dec cx ; more? jnz bootHackFile ; bootHackDone: ; adjust CS:IP according to header mov bx, ds:[si][14h] ; ip add ax, ds:[si][16h] ; cs bootExecFile: mov dl, BS.bs32DriveNumber push ax push bx retf ;--------------------------------------------------------------------------- ; fat32ReadCluster ; ; Entry: ; es = cluster buffer segment ; esi = cluster number ; Exit: ; ebx = number of bytes read ; esi = cluster number ; fat32ReadCluster PROC NEAR lea eax, [esi-2] movzx ecx, BPB.bpbSectorsPerCluster mul ecx add eax, VAR.stdDataArea call ext13ReadSector movzx eax, BPB.bpbBytesPerSector xchg eax, esi shl eax, 2 div esi push dx movzx esi, BPB.bpbReservedSectors add esi, eax movzx eax, BYTE PTR BPB.bpb32Flags and al, EXT_FLAGS_FAT_MASK mul BPB.bpb32SectorsPerFAT add eax, esi pop si mov cl, 1 push es push ebx mov es, VAR.stdFATSegment call ext13ReadSector mov esi, es:[si] pop ebx pop es and esi, 0FFFFFFFh cmp esi, 0FFFFFF8h cmc ret fat32ReadCluster ENDP ;--------------------------------------------------------------------------- ; ext13ReadSector - read sector(s) using INT13 extensions ; ; Entry: ; es = sector buffer segment ; cx = sector count ; eax = sector number (32-bit LBA) ; Exit: ; cx = 1 ; ebx = number of bytes read ; ext13ReadSector PROC NEAR push dx push si add eax, BPB.bpbHiddenSectors push LARGE 0 ; LBA upper 32-bits push eax ; LBA lower 32-bits push es ; buffer seg push bx ; buffer ofs push cx ; sector read count push 0010h ; record size mov ax, BPB.bpbBytesPerSector mul cx push dx ; push ax ; ebx = bytes read pop ebx ; push ss ; pop ds ; mov si, sp ; ds:si -> I/O packet mov ah, 42h mov dl, BS.bs32DriveNumber int 13h add sp, 16 ; discard I/O packet pop si pop dx ret ext13ReadSector ENDP ; list of possible boot images szImageListDef LABEL BYTE DB "LOADER EXE" szImageListEnd LABEL BYTE BOOT_MAGIC_HERE codeSegment ENDS END