;=----------------------------------------------------------------------------=; ; GNU GPL OS/K ; ; ; ; Authors: spectral` ; ; NeoX ; ; ; ; Desc: Bootsector for OS/K INCLUDED FUNCTIONS ; ; (x86_64 architecture only) ; ;=----------------------------------------------------------------------------=; [BITS 16] read_clusters: ;---------------------------------------------------; ; Read file clusters, starting at the given cluster,; ; expects FAT to be loaded into the disk buffer. ; ; Please note that this may allocate up to 128KB ; ; of ram. ; ; ; ; Expects: AX = Starting cluster ; ; ES:DI = Location to load clusters ; ; ; ; Returns: None ; ; ; ;---------------------------------------------------; pusha push es .cluster_loop: xor bh, bh xor dx, dx push ax ; Get the cluster start = (cluster - 2) * sectorsPerCluster + UserData sub ax, 2 ; Subtract 2 mov bl, byte [sectorsPerCluster] ; Sectors per cluster is a byte value mul bx ; multiply (cluster - 2) * sectorsPerCluster add ax, word [UserData] ; add the UserData xor ch, ch mov cl, byte [sectorsPerCluster] ; Sectors to read call read_sectors ; Read the sectors pop ax ; Current cluster number xor dx, dx ;; Calculate next sector for FAT16 (cluster * 2) mov bx, 2 ; Multiply the cluster by two (cluster is in ax) mul bx ;; Load sector in RAM push ds push si mov si, BUFFER_SEG mov ds, si ; Temporarly set ds:si to the FAT buffer mov si, BUFFER_OFF add si, ax ; Point to the next cluster in the FAT entry mov ax, word [ds:si] ; Load ax to the next cluster in FAT pop si pop ds ;; Next cmp ax, 0xfff8 ; Check if we are at the end of the file? jae .done add di, 512 ; Add to the pointer offset jnc .cluster_loop ;; Correct the buffer because an error will occur if the buffer in memory mov dx, es ; overlaps a 64k page boundry, when di overflows add dh, 0x10 ; it will trigger the carry flag, so correct mov es, dx ; extra segment by 0x1000 jmp .cluster_loop ; Load the next file cluster .done: pop es popa ret read_sectors: ;---------------------------------------------------; ; Read sectors starting at a given sector by ; ; the given times and load into a buffer. Please ; ; note that this may allocate up to 128KB of ram. ; ; ; ; Expects: AX = Starting sector ; ; CX = Number of sectors to read ; ; ES:DI = Location to load sectors ; ; ; ; Returns: None ; ; ; ;---------------------------------------------------; pusha push es mov bx, di ; Convert es:di to es:bx for int 13h .sector_loop: push ax push cx xor dx, dx div word [sectorsPerTrack] ; Divide the lba (value in ax) by sectorsPerTrack mov cx, dx ; Save the absolute sector value inc cx xor dx, dx ; Divide by the number of heads div word [heads] ; to get absolute head and track values mov dh, dl ; Move the absolute head into dh mov ch, al ; Low 8 bits of absolute track shl ah, 1 ; High 2 bits of absolute track shl ah, 1 shl ah, 1 shl ah, 1 shl ah, 1 shl ah, 1 or cl, ah ; Now cx is set with respective track and sector numbers mov dl, byte [Bootdrv] ; Set correct Bootdrv for int 13h mov di, 21 ; Try five times to read the sector because I love 21 .attempt_read: mov ax, 0x0201 ; Read Sectors func of int 13h, read one sector int 0x13 ; Call int 13h (BIOS disk I/O) jnc .read_ok ; If no carry set, the sector has been read xor ah, ah ; Reset Bootdrv func of int 13h int 0x13 ; Call int 13h (BIOS disk I/O) dec di ; Decrease read attempt counter jnz .attempt_read ; Try to read the sector again mov si, DiskError ; Error reading the disk :/ call print jmp reboot .read_ok: pop cx pop ax inc ax ; Increase the next sector to read add bx, word [bytesPerSector] ; Add to the buffer address for the next sector jnc .next_sector ;; Fixing buffer because an error will occur if the buffer in memory mov dx, es ; overlaps a 64k page boundry, when bx overflows add dh, 0x10 ; it will trigger the carry flag, so correct mov es, dx ; es segment by 0x1000 .next_sector: loop .sector_loop pop es popa ret print: ;---------------------------------------------------; ; Print out a simple string. ; ; ; ; Expects: DS:SI = String to print ; ; ; ; Returns: None ; ; ; ;---------------------------------------------------; lodsb ; Load byte from ds:si to al or al, al ; If al is empty stop looping jz .done ; Done looping and return mov ah, 0x0e ; Teletype output int 0x10 ; Video interupt jmp print ; Loop untill string is null .done: ret reboot: xor ax, ax int 0x16 ; Get a single keypress mov ah, 0x0e ; Teletype output mov al, 0x0d ; Carriage return int 0x10 ; Video interupt mov al, 0x0a ; Line feed int 0x10 ; Video interupt mov al, 0x0a ; Line feed int 0x10 ; Video interupt xor ax, ax int 0x19 ; Reboot the system