cpu 286 bits 16 org 0x7c00 COLUMNS equ 80 ROWS equ 25 WALLPAPER equ 0x500 DIRENTS equ 0x2000 DIRENT_SIZE equ 32 FILE_MAX_SIZE equ 128 jmp 0:start start: cld ; Set up segments and stack mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, $$ ; Clear BSS ;xor al, al mov di, _bss_start mov cx, _bss_end - _bss_start rep stosb mov [boot_disk], dl initialize_mouse: ; Initialize mouse ; https://www.ctyme.com/intr/rb-1601.htm mov ax, 0xc205 mov bh, 3 ; TODO: This is the usual PS/2 mouse packet size, but is it correct here? int 0x15 jc .error ; Set handler address ; https://www.ctyme.com/intr/rb-1603.htm mov ax, 0xc207 ; es is already set correctly mov bx, mouse_handler int 0x15 jc .error ; Enable mouse ; https://www.ctyme.com/intr/rb-1596.htm mov ax, 0xc200 mov bh, 1 int 0x15 jc .error jmp .done .error: ; https://www.ctyme.com/intr/rb-1601.htm mov ax, 0xc201 int 0x15 jmp initialize_mouse .done: load_wallpaper: mov si, wallpaper_name call open_file mov bx, WALLPAPER call read_sectors ; TODO: error management? Surely this works... load_shell: push word 0x1000 pop es mov si, shell_name call open_file xor bx, bx call read_sectors call 0x1000:0 initialize_screen: ; Disable text cursor mov ah, 0x01 mov ch, 0x20 int 0x10 call draw_wallpaper call flip_mouse_cursor mainloop: mov bx, [mouse_x] shr bx, 1 mov cx, [mouse_y] shr cx, 1 shr cx, 1 cmp [mouse_column], bl jne .update_cursor cmp [mouse_row], cl jne .update_cursor hlt jmp mainloop .update_cursor: call flip_mouse_cursor mov [mouse_column], bl mov [mouse_row], cl call flip_mouse_cursor jmp mainloop ; ------------------------------------------------------------------ ; Drawing subroutines ; ------------------------------------------------------------------ draw_wallpaper: pusha push es push ds xor ax, ax mov ds, ax push word 0xb800 pop es mov si, WALLPAPER xor di, di mov cx, 80*25 rep movsw pop ds pop es popa ret flip_mouse_cursor: pusha push es push word 0xb800 pop es ; Column xor bh, bh mov bl, [mouse_column] shl bx, 1 ; Row mov al, [mouse_row] mov cl, COLUMNS*2 mul cl add bx, ax ; Swap foreground and background colours inc bx mov al, [es:bx] mov cl, 4 ror al, cl mov [es:bx], al pop es popa ret ; ------------------------------------------------------------------ ; Disk subroutines ; ------------------------------------------------------------------ ; in: ; ax = LBA of first sector ;; bl = drive number ; cx = number of sectors to read (must be at least 1) ; es:bx = output buffer read_sectors: pusha xor di, di .loop: call modify_sector inc ax add bx, 512 loop .loop popa ret ; in: ; ax = LBA of first sector ;; bl = drive number, use [boot_disk] for now ; es:bx = output buffer ; di = 0x0100 for write, 0x0000 for read modify_sector: pusha push ds xor cx, cx mov ds, cx ;mov cx, 18 mov cl, 18 div cx ; cl = sector (1…18) mov cl, dl inc cl ; dh = head (0…1) mov dh, 1 and dh, al ; ch = cylinder shr ax, 1 mov ch, al ; dl = drive number mov dl, [ds:boot_disk] .retry: mov ax, 0x0201 ; read/write one sector add ax, di int 0x13 jc .error pop ds popa ret .error: ; Reset the disk system unconditionally, as we have no ; kernel panic handler to go to after 3 tries and proper ; error handling would take too much code xor ah, ah int 0x10 jmp .retry ; ------------------------------------------------------------------ ; Filesystem ; ------------------------------------------------------------------ wallpaper_name: db 'bg.bin', 0 shell_name: db 'shell.bin', 0 ; in: ; ds:si = file name ; out: ; ax = LBA of first sector, 0 if no space left ; cx = length in sectors open_file: push si push di push bx push es ; Stolen from https://stackoverflow.com/a/72746473, get strlen in cx mov cx, ds mov es, cx mov di, si mov cx, -1 xor ax, ax repne scasb not cx dec cx mov es, ax ;mov ax, 1 mov al, 1 mov bx, DIRENTS xor di, di call modify_sector mov ax, 2 mov di, bx .loop: cmp word [es:di], 0 je .create_file inc di inc di pusha repe cmpsb popa je .success add ax, FILE_MAX_SIZE add di, DIRENT_SIZE - 2 cmp di, DIRENTS + 0x200 jl .loop .error: xor ax, ax ; Return with mangled cx .success: mov cx, [es:di - 2] .return: pop es pop bx pop di pop si ret .create_file: ; TODO: zero out the sector for this file? inc word [es:di] inc di inc di rep movsb push ax mov ax, 1 ;mov bx, DIRENTS mov di, 0x0100 ; write call modify_sector pop ax ;mov cx, 1 mov cl, 1 jmp .return ; ------------------------------------------------------------------ ; Mouse callback ; ------------------------------------------------------------------ Y_OVERFLOW equ 0x80 X_OVERFLOW equ 0x40 Y_NEGATIVE equ 0x20 X_NEGATIVE equ 0x10 BUTTONS equ 0x03 X_MAX_VALUE equ 2*COLUMNS-1 Y_MAX_VALUE equ 4*ROWS-1 mouse_handler: pusha push ds mov ax, cs mov ds, ax mov bp, sp mov bx, [bp+2*9+10] ; status test bl, X_OVERFLOW jnz .x_end .x: mov ax, [bp+2*9+8] ; X test bl, X_NEGATIVE jnz .x_negative .x_nonnegative: add [mouse_x], ax cmp word [mouse_x], X_MAX_VALUE jb .x_end mov word [mouse_x], X_MAX_VALUE jmp .x_end .x_negative: neg al sub [mouse_x], ax jnc .x_end mov word [mouse_x], 0 .x_end: test bl, Y_OVERFLOW jnz .y_end .y: mov ax, [bp+2*9+6] ; Y test bl, Y_NEGATIVE jnz .y_negative .y_nonnegative: ; Y-axis is inverted sub [mouse_y], ax jnc .y_end mov word [mouse_y], 0 jmp .y_end .y_negative: neg al add [mouse_y], ax cmp word [mouse_y], Y_MAX_VALUE jb .y_end mov word [mouse_y], Y_MAX_VALUE .y_end: and bl, BUTTONS mov [mouse_buttons], bl pop ds popa retf ; ------------------------------------------------------------------ ; Debug routines ; ------------------------------------------------------------------ %if 0 hexprint16: xchg ah, al call hexprint8 xchg ah, al hexprint8: push ax push cx mov cl, 4 shr al, cl call hexprint4 pop cx pop ax hexprint4: push ax and al, 0xf cmp al, 10 jb .digit09 add al, 'a' - '0' - 10 .digit09: add al, '0' mov ah, 0x0e int 0x10 pop ax ret hang: hlt jmp hang %endif ; ------------------------------------------------------------------ ; Padding and boot sector signature ; ------------------------------------------------------------------ %ifndef SIZE times 510-($-$$) db 0 %endif db 0x55 db 0xaa ; ------------------------------------------------------------------ ; Zero-initialized variables ; ------------------------------------------------------------------ section .bss _bss_start: mouse_x resw 1 mouse_y resw 1 mouse_buttons resb 1 mouse_column resb 1 mouse_row resb 1 boot_disk resb 1 _bss_end: