use16 ? equ 0 ImageLoadSeg equ 60h ORG 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Boot sector starts here ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; jmp start nop bsOemName DB '*-SINtez' ; 0x03 ;;;;;;;;;;;;;;;;;;;;; ;; BPB starts here ;; ;;;;;;;;;;;;;;;;;;;;; bpbBytesPerSector DW 0x200 ; 0x0B bpbSectorsPerCluster DB 1 ; 0x0D bpbReservedSectors DW 1 ; 0x0E bpbNumberOfFATs DB 2 ; 0x10 bpbRootEntries DW 224 ; 0x11 bpbTotalSectors DW 2880 ; 0x13 bpbMedia DB 0xF0 ; 0x15 bpbSectorsPerFAT DW 9 ; 0x16 bpbSectorsPerTrack DW 18 ; 0x18 bpbHeadsPerCylinder DW 2 ; 0x1A bpbHiddenSectors DD 0 ; 0x1C bpbTotalSectorsBig DD 0 ; 0x20 ;;;;;;;;;;;;;;;;;;; ;; BPB ends here ;; ;;;;;;;;;;;;;;;;;;; bsDriveNumber DB 0 ; 0x24 bsUnused DB 0 ; 0x25 bsExtBootSignature DB 29h ; 0x26 bsSerialNumber DD 2a876CE1h ; 0x27 bsVolumeLabel DB 'X boot disk' ; 0x2B bsFileSystem DB 'FAT12 ' ; 0x36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Boot sector code starts here ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; start: cld ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; How much RAM is there? ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; int 12h ; get conventional memory size (in KBs) shl ax, 6 ; and convert it to paragraphs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reserve some memory for the boot sector and the stack ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; sub ax, 512 / 16 ; reserve 512 bytes for the boot sector code mov es, ax ; es:0 -> top - 512 sub ax, 2048 / 16 ; reserve 2048 bytes for the stack mov ss, ax ; ss:0 -> top - 512 - 2048 mov sp, 2048 ; 2048 bytes for the stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Copy ourself to top of memory ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov cx, 256 mov si, 7C00h xor di, di mov ds, di rep movsw ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Jump to relocated code ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; push es push word main retf main: push cs pop ds mov [bsDriveNumber], dl ; store boot drive number ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reserve some memory for a FAT12 image (6KB max) and load it whole ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax, [bpbBytesPerSector] shr ax, 4 ; ax = sector size in paragraphs mov cx, [bpbSectorsPerFAT] ; cx = FAT size in sectors mul cx ; ax = FAT size in paragraphs mov di, ss sub di, ax mov es, di xor bx, bx ; es:bx -> buffer for the FAT mov eax, [bpbHiddenSectors] mov edx, [bpbHiddenSectors+2] add ax, [bpbReservedSectors] adc dx, bx ; dx:ax = LBA call ReadSector ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reserve some memory for a root directory and load it whole ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov bx, ax mov di, dx ; save LBA to di:bx mov ax, 32 mov si, [bpbRootEntries] mul si div word [bpbBytesPerSector] mov cx, ax ; cx = root directory size in sectors mov al, [bpbNumberOfFATs] cbw mul word [bpbSectorsPerFAT] add ax, bx adc dx, di ; dx:ax = LBA push es ; push FAT segment (2nd parameter) push word ImageLoadSeg pop es xor bx, bx ; es:bx -> buffer for root directory call ReadSector add ax, cx adc dx, bx ; adjust LBA for cluster data push dx push ax ; push LBA for data (1st parameter) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Look for a COM/EXE program to be load and run ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov di, bx ; es:di -> root entries array mov dx, si ; dx = number of root entries mov si, ProgramName ; ds:si -> program name ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Looks for a file with particular name ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Input: DS:SI -> file name (11 chars) ;; ;; ES:DI -> root directory array ;; ;; DX = number of root entries ;; ;; Output: SI = cluster number ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FindName: mov cx, 11 FindNameCycle: cmp byte [es:di], ch je FindNameFailed ; end of root directory pusha repe cmpsb popa je FindNameFound add di, 32 dec dx jnz FindNameCycle ; next root entry FindNameFailed: jmp ErrFind FindNameFound: mov si, [es:di+1Ah] ; si = cluster no. ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Load entire a program ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;; ReadNextCluster: call ReadCluster cmp si, 0FF8h jc ReadNextCluster ; if not End Of File ;;;;;;;;;;;;;;;;;;; ;; Type checking ;; ;;;;;;;;;;;;;;;;;;; cli ; for stack adjustments mov ax, ImageLoadSeg mov es, ax cmp word [es:0], 5A4Dh ; "MZ" signature? je RelocateEXE ; yes, it's an EXE program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Setup and Run COM program ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax, es sub ax, 10h ; "org 100h" stuff :) mov es, ax mov ds, ax mov ss, ax xor sp, sp push es push word 100h jmp Run ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Relocate, setup and run EXE program ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RelocateEXE: mov ds, ax add ax, [ds:08h] ; ax = image base mov cx, [ds:06h] ; cx = reloc items mov bx, [ds:18h] ; bx = reloc table pointer jcxz RelocationDone ReloCycle: mov di, [ds:bx] ; 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 loop ReloCycle RelocationDone: mov bx, ax add bx, [ds:0Eh] mov ss, bx ; ss for EXE mov sp, [ds:10h] ; sp for EXE add ax, [ds:16h] ; cs push ax push word [ds:14h] ; ip Run: mov dl, [cs:bsDriveNumber] ; let program know boot drive sti retf ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reads a FAT12 cluster ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Inout: ES:BX -> buffer ;; ;; SI = cluster no ;; ;; Output: SI = next cluster ;; ;; ES:BX -> next addr ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ReadCluster: mov bp, sp lea ax, [si-2] xor ch, ch mov cl, [bpbSectorsPerCluster] ; cx = sector count mul cx add ax, [ss:bp+1*2] adc dx, [ss:bp+2*2] ; dx:ax = LBA call ReadSector mov ax, [bpbBytesPerSector] shr ax, 4 ; ax = paragraphs per sector mul cx ; ax = paragraphs read mov cx, es add cx, ax mov es, cx ; es:bx updated mov ax, 3 mul si shr ax, 1 xchg ax, si ; si = cluster * 3 / 2 push ds mov ds, [ss:bp+3*2] ; ds = FAT segment mov si, [ds:si] ; si = next cluster pop ds jnc ReadClusterEven shr si, 4 ReadClusterEven: and si, 0FFFh ; mask cluster value ReadClusterDone: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Reads a sector using BIOS Int 13h fn 2 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Input: DX:AX = LBA ;; ;; CX = sector count ;; ;; ES:BX -> buffer address ;; ;; Output: CF = 1 if error ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ReadSector: pusha ReadSectorNext: mov di, 5 ; attempts to read ReadSectorRetry: pusha div word [bpbSectorsPerTrack] ; ax = LBA / SPT ; dx = LBA % SPT = sector - 1 mov cx, dx inc cx ; cx = sector no. xor dx, dx div word [bpbHeadsPerCylinder] ; ax = (LBA / SPT) / HPC = cylinder ; dx = (LBA / SPT) % HPC = head mov ch, al ; ch = LSB 0...7 of cylinder no. shl ah, 6 or cl, ah ; cl = MSB 8...9 of cylinder no. + sector no. mov dh, dl ; dh = head no. mov dl, [bsDriveNumber] ; dl = drive no. mov ax, 201h ; al = sector count ; ah = 2 = read function no. int 13h ; read sectors jnc ReadSectorDone ; CF = 0 if no error xor ah, ah ; ah = 0 = reset function int 13h ; reset drive popa dec di jnz ReadSectorRetry ; extra attempt jmp ErrRead ReadSectorDone: popa dec cx jz ReadSectorDone2 ; last sector add bx, [bpbBytesPerSector] ; adjust offset for next sector add ax, 1 adc dx, 0 ; adjust LBA for next sector jmp ReadSectorNext ReadSectorDone2: popa ret ;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Error Messaging Code ;; ;;;;;;;;;;;;;;;;;;;;;;;;;; ErrRead: mov si, MsgErrRead jmp Error ErrFind: mov si, MsgErrFind Error: mov ah, 0Eh mov bx, 7 lodsb int 10h ; 1st char lodsb int 10h ; 2nd char jmp $ ; hang ;;;;;;;;;;;;;;;;;;;;;; ;; String constants ;; ;;;;;;;;;;;;;;;;;;;;;; MsgErrRead db "RE" MsgErrFind db "NF" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Name of a program to be load and run ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ProgramName db 'KERNEL EXE' ; name and extension must be padded ; with spaces (11 bytes total) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Fill free space with zeroes ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; times 510- ($-0) db 0 ;;;;;;;;;;;;;;;;;;;;;;;;;; ;; End of the sector ID ;; ;;;;;;;;;;;;;;;;;;;;;;;;;; dw 0xaa55