ORG 7C00h BITS 16 jmp short main nop ; Define Fat12 header bdb_oem: db 'MSWIN4.1' bdb_bytes_per_sector: dw 512 bdb_sectors_per_cluster: db 1 bdb_reserved_sectors: dw 1 bdb_fat_count: db 2 bdb_dir_entries_count: dw 0E0h bdb_total_sectors: dw 2880 bdb_media_descriptor_type: db 0F0h bdb_sectors_per_fat: dw 9 bdb_sectors_per_track: dw 18 bdb_heads: dw 2 bdb_hidden_sectors: dd 0 bdb_large_sector_count: dd 0 ; extended boot record ebr_drive_number: db 0 db 0 ebr_signature: db 29h ebr_volume_id: db 12h, 34h, 56h, 78h ebr_volume_label: db 'CrawShaw OS' ebr_system_id: db 'FAT12 ' main: ; Setup registers mov ax, 0 mov ds, ax ; ds = data segment pointer mov es, ax ; es = extra segment pointer mov ss, ax ; ss = stack pointer mov sp, 7C00h ; Read from disk ;mov [ebr_drive_number], dl ;mov ax, 1 ;mov cl, 1 ;mov bx, 7E00h ;call disk_read ; Output boot text mov si, boot_text call print_string ; Load kernel ; 4 segments: ; reserved segment (bdb_reserved_segments, 1) ; FAT: (sectors_per_fat * fat_count) 9*2=18 ; root dir: gives location of data ; data: stores the actual data ; Get LBA of root dir mov ax, [bdb_sectors_per_fat] mov bl, [bdb_fat_count] xor bh,bh ; clear bh mul bx ; 9 * 2 = 18 add ax, [bdb_reserved_sectors] ; The LBA of root dir push ax ; Push to stack mov ax, [bdb_dir_entries_count] shl ax,5 ; ax *= 32 (shifting 5 times) xor dx,dx ; Clear dx div word [bdb_bytes_per_sector] ;32*num of entries)/bytes per sector test dx,dx ; See if there's a remainder jz root_dir_after inc ax ; Add one if there's a remainder root_dir_after: mov cl, al pop ax ; LBA of root dir mov dl, [ebr_drive_number] mov bx, buffer call disk_read xor bx,bx ; clear bx mov di, buffer ; Loaded root dir into memory search_for_kernel: mov si, file_kernel_bin ; Move the name of the kernel into si mov cx, 11 push di ; Preserve di repe cmpsb ; Repeat a comparison of bytes between kernel name and current bytes until it finds a match pop di ; Retrieve di je found_kernel add di, 32 ; Next directory entry inc bx cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist jl search_for_kernel ; Repeat search jmp kernel_not_found ; If the last dir has been searched, then there is no kernel kernel_not_found: mov si, kernel_load_error call print_string hlt jmp halt found_kernel: mov si, kernel_found_text call print_string ; Find kernel cluster mov ax, [di+26] mov [kernel_cluster], ax mov ax, [bdb_reserved_sectors] mov bx, buffer mov cl, [bdb_sectors_per_fat] mov dl, [ebr_drive_number] call disk_read ; Load FAT from disk into memory ; Load kernel into memory mov bx, kernel_load_segment mov es, bx mov bx, kernel_load_offset ; Setup memory that kernel will be loaded into load_kernel_loop: mov ax, [kernel_cluster] add ax, 31 ; Setup offset so we can read the particular cluster mov cl, 1 ;sectors to read mov dl, [ebr_drive_number] call disk_read add bx, [bdb_bytes_per_sector] ; (kernel_cluster * 3) / 2 mov ax, [kernel_cluster] mov cx, 3 mul cx mov cx, 2 div cx ; setup buffers mov si, buffer add si, ax mov ax, [ds:si] or dx,dx jz even odd: shr ax, 4 ;shift ax 4 jmp next_cluster_after even: and ax, 0fffh ; Gives the other 12 bits next_cluster_after: cmp ax, 0ff8h ; If the value is ff8h or bigger then we've reached the end of FAT jae read_finish mov [kernel_cluster], ax jmp load_kernel_loop read_finish: ; Load kernel mov dl, [ebr_drive_number] mov ax, kernel_load_segment mov ds, ax mov es, ax jmp kernel_load_segment:kernel_load_offset ; Jump to the kernel code hlt halt: jmp halt ; LBA = index of data segment on disk ; CHS = cylinder, header, sector ; input, LBA index: ax ; sector number: cx [0-5] ; cylinder: cx [6-15] ; head: dh lba_to_chs: push ax push dx xor dx,dx ; clear dx div word [bdb_sectors_per_track] ;(LBA % sectors per track) + 1 = sector inc dx ; sector, dx stores the remainder so we increment that. mov cx,dx xor dx,dx ; clear dx div word [bdb_heads] mov dh,dl ; head mov ch,al shl ah, 6 or CL, AH ; cylinder pop ax mov dl,al pop ax RET disk_read: push ax push bx push cx push dx push di call lba_to_chs mov ah, 02h ; repeat drive read 3 times (incase of random error) mov di, 3 ; counter retry: stc int 13h jnc done_read call disk_reset ; Reset drivers of disk dec di test di, di jnz retry fail_disk_read: mov si, disk_read_fail call print_string hlt jmp halt disk_reset: pusha mov ah, 0 ; Reset drive stc int 13h jc fail_disk_read popa ret done_read: pop di pop dx pop cx pop bx pop ax ret ; SI = pointer to start of string to be printed print_string: push si push ax push bx mov ah, 0Eh ; int 10h teletype function, we're telling the BIOS we will print something .repeat: lodsb ; Get char from si into al cmp al, 0 ; Compare al to 0 je .done ; If char is zero, end of string mov bh, 0 int 10h ; Otherwise, print it jmp .repeat ; And move on to next char .done: ; Print newline mov ah, 0Eh mov al, 13 int 10h mov al, 10 int 10h ; Exit function pop bx pop ax pop si ret boot_text: db '[OK] Boot sequence begun...', 0 kernel_found_text: db '[OK] Kernel located...', 0 disk_read_fail: db '[ERR] Failed to read disk!', 0 file_kernel_bin: db 'KERNEL BIN' ; Must have a double space between KERNEL and BIN kernel_load_error: db '[ERR] Kernel not found!', 0 kernel_cluster: dw 0 kernel_load_segment: equ 2000h kernel_load_offset: equ 0 times 510-($-$$) db 0 ; Fill up the next 510 bits with 0's dw 0AA55h ; D buffer: