ponydos/ponydos.asm

535 lines
8.6 KiB
NASM
Raw Permalink Normal View History

2023-03-19 17:28:30 +00:00
%ifdef SYMBOLS
[map symbols]
%endif
%include "ponydos_static.inc"
2023-03-18 13:55:53 +00:00
cpu 286
2022-02-11 16:16:49 +00:00
bits 16
org 0x7c00
2023-03-29 10:28:36 +00:00
X_SENSITIVITY equ 3
Y_SENSITIVITY equ 3
2023-03-22 23:08:07 +00:00
2022-02-11 16:16:49 +00:00
jmp 0:start
2023-03-18 13:55:53 +00:00
2023-03-20 18:46:29 +00:00
initialize_mouse_error:
; https://www.ctyme.com/intr/rb-1601.htm
mov ax, 0xc201
int 0x15
jmp initialize_mouse
2022-02-11 16:16:49 +00:00
start:
cld
; Set up segments and stack
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
2023-03-18 12:31:23 +00:00
xor sp, sp
2022-02-11 16:16:49 +00:00
2023-02-06 15:15:47 +00:00
; Clear BSS
2023-03-16 10:10:03 +00:00
;xor al, al
2023-02-06 15:15:47 +00:00
mov di, _bss_start
mov cx, _bss_end - _bss_start - 1
2023-02-06 15:15:47 +00:00
rep stosb
; At boot_disk
mov [di], dl
2023-03-11 15:49:55 +00:00
2023-01-30 16:56:16 +00:00
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
2023-03-19 14:02:28 +00:00
jc initialize_mouse_error
2023-01-30 16:56:16 +00:00
; 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
2023-03-19 14:02:28 +00:00
jc initialize_mouse_error
2023-01-30 16:56:16 +00:00
; Enable mouse
; https://www.ctyme.com/intr/rb-1596.htm
mov ax, 0xc200
mov bh, 1
int 0x15
2023-03-19 14:02:28 +00:00
jc initialize_mouse_error
2023-02-06 15:45:26 +00:00
2023-03-17 23:05:32 +00:00
load_shell:
2023-03-18 06:42:18 +00:00
push word 0x1000
pop es
2023-03-17 23:05:32 +00:00
mov si, shell_name
xor dx, dx
2023-03-19 17:28:30 +00:00
call 0:open_file
2023-03-17 23:05:32 +00:00
xor bx, bx
xor di, di ; read
call 0:modify_sectors
2023-03-18 13:55:53 +00:00
; TODO: error management? Surely this works...
2023-03-17 23:05:32 +00:00
call 0x1000:PROC_INITIALIZE_ENTRYPOINT
2023-03-17 23:05:32 +00:00
2023-03-11 15:49:55 +00:00
initialize_screen:
2023-02-06 15:45:26 +00:00
; Disable text cursor
2023-02-06 16:02:21 +00:00
mov ah, 0x01
mov ch, 0x20
int 0x10
; Set up segments for drawing routines
push word 0xb800
pop es
mov di, mouse_column
2023-03-19 18:50:24 +00:00
2022-02-11 16:16:49 +00:00
mainloop:
2023-03-20 16:17:45 +00:00
xor al, al
xchg byte [di - mouse_column + redraw], al
test al, al
jz .draw_end
.draw:
call draw_wallpaper
; Draw windows
2023-03-20 18:46:29 +00:00
xor al, al ; WM_PAINT
2023-03-20 18:18:49 +00:00
call window_event
2023-03-19 18:50:24 +00:00
2023-03-20 18:18:49 +00:00
call flip_mouse_cursor
2022-02-11 16:16:49 +00:00
2023-03-20 18:18:49 +00:00
.draw_end:
xor al, al
xchg byte [di - mouse_column + mouse_change], al
test al, al
jz .mouse_change_end
.mouse_change:
mov cx, [di - mouse_column + mouse_x]
2023-03-22 23:08:07 +00:00
shr cx, X_SENSITIVITY
2023-03-20 18:18:49 +00:00
mov bx, [di - mouse_column + mouse_y]
2023-03-22 23:08:07 +00:00
shr bx, Y_SENSITIVITY
2023-03-20 18:18:49 +00:00
mov ch, bl
2023-02-06 15:45:26 +00:00
call flip_mouse_cursor
2023-03-20 18:18:49 +00:00
mov [di], cx
2023-02-06 15:45:26 +00:00
call flip_mouse_cursor
2023-03-20 18:18:49 +00:00
mov dl, [di - mouse_column + mouse_buttons]
2023-03-20 18:46:29 +00:00
mov al, WM_MOUSE
2023-03-20 18:18:49 +00:00
call window_event
.mouse_change_end:
2023-03-20 18:46:29 +00:00
mov ah, 1
int 0x16
jz .key_end
.key:
xor ah, ah
int 0x16
mov cx, ax
mov al, WM_KEYBOARD
call window_event
.key_end:
2023-03-20 18:18:49 +00:00
hlt
jmp mainloop
2023-02-06 15:45:26 +00:00
2023-03-20 18:18:49 +00:00
; requires:
; ds = 0
; di = mouse_column
; in:
2023-03-20 18:46:29 +00:00
; al = event
2023-03-20 18:18:49 +00:00
; out:
; clobbers bx
2023-03-20 18:46:29 +00:00
; clobbers bp
2023-03-20 18:18:49 +00:00
window_event:
push cs ; Return segment
push word draw_wallpaper.ret ; Return offset
mov bx, [di - mouse_column + window_chain_head]
mov bp, 0xf000
and bp, bx
push bp ; Call segment
;push word 0 ; Call offset
push cs ; Call offset
retf
2023-03-11 15:49:55 +00:00
; ------------------------------------------------------------------
; Drawing subroutines
; ------------------------------------------------------------------
2023-03-19 14:23:30 +00:00
; in:
; bx = width of input buffer
; cx = width of rectangle
; dx = height of rectangle (must be at least 1)
2023-03-19 14:23:30 +00:00
; ds:si = beginning of source data
; di = X
; bp = Y
2023-03-19 17:28:30 +00:00
; [Far calls only]
2023-03-19 14:23:30 +00:00
draw_rect:
pusha
push es
push word 0xb800
pop es
; Calculate the starting address in the screen buffer
; Assumes COLUMNS is 80
; X columns * 2 bytes / column
shl di, 1
; Y rows * 80 cells / row * 2 bytes / cell = Y * 160 bytes
; bp * 160 = bp * 128 + bp * 32 = (bp<<7) + (bp<<5)
shl bp, 5
add di, bp
shl bp, 2
add di, bp
; Convert widths to bytes
shl bx, 1
.loop:
; Copy a row
2023-03-19 10:32:49 +00:00
pusha
rep movsw
2023-03-19 10:32:49 +00:00
popa
2023-03-19 14:23:30 +00:00
; Move to the next row in the input buffer
add si, bx
; Move to the next row in the screen buffer
add di, 2*COLUMNS
2023-03-19 10:32:49 +00:00
dec dx
; Any rows left to copy?
jnz .loop
2023-03-19 14:23:30 +00:00
pop es
popa
2023-03-19 17:28:30 +00:00
retf
2023-03-19 14:23:30 +00:00
; requires:
; ds = 0
; es = 0xb800
2023-03-11 15:49:55 +00:00
draw_wallpaper:
pusha
2023-03-11 15:49:55 +00:00
2023-03-18 13:55:53 +00:00
mov si, GLOBAL_WALLPAPER
2023-03-11 15:49:55 +00:00
xor di, di
mov cx, 80*25
rep movsw
popa
2023-03-20 18:18:49 +00:00
.ret: ret ; window_event needs this
2023-03-11 15:49:55 +00:00
; requires:
; di = mouse_column
; ds = 0
; es = 0xb800
2023-02-06 15:45:26 +00:00
flip_mouse_cursor:
pusha
2023-02-06 15:45:26 +00:00
mov bx, [di]
mov al, bh
2023-02-06 15:45:26 +00:00
; Column
xor bh, bh
shl bx, 1
; Row
mov cl, COLUMNS*2
mul cl
add bx, ax
; Swap foreground and background colours
inc bx
2023-03-19 17:03:16 +00:00
ror byte [es:bx], 4
2023-02-06 15:45:26 +00:00
popa
2023-02-06 15:45:26 +00:00
ret
2022-02-11 16:16:49 +00:00
2023-03-11 15:49:55 +00:00
; ------------------------------------------------------------------
; Disk subroutines
; ------------------------------------------------------------------
; in:
; ax = LBA of first sector
2023-03-16 10:10:03 +00:00
;; bl = drive number
2023-03-11 15:49:55 +00:00
; cx = number of sectors to read (must be at least 1)
2023-03-16 10:10:03 +00:00
; es:bx = output buffer
; di = 0x0100 for write, 0x0000 for read
2023-03-19 17:28:30 +00:00
; [Far calls only]
modify_sectors:
pusha
2023-03-11 15:49:55 +00:00
.loop:
2023-03-16 10:42:22 +00:00
call modify_sector
2023-03-11 15:49:55 +00:00
inc ax
2023-03-16 10:10:03 +00:00
add bx, 512
2023-03-11 15:49:55 +00:00
loop .loop
popa
2023-03-19 17:28:30 +00:00
retf
2023-03-11 15:49:55 +00:00
; in:
2023-03-16 10:42:22 +00:00
; 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
2023-03-16 10:42:22 +00:00
mov cl, 18
div cl
2023-03-11 15:49:55 +00:00
; cl = sector (1…18)
mov cl, ah
2023-03-11 15:49:55 +00:00
inc cl
; dh = head (0…1)
mov dh, 1
and dh, al
; ch = cylinder
shr al, 1
2023-03-11 15:49:55 +00:00
mov ch, al
; dl = drive number
mov dl, [cs:boot_disk]
2023-03-11 15:49:55 +00:00
2023-03-13 12:40:28 +00:00
.retry:
2023-03-16 10:42:22 +00:00
mov ax, 0x0201 ; read/write one sector
add ax, di
2023-03-11 15:49:55 +00:00
int 0x13
2023-03-13 12:40:28 +00:00
jc .error
2023-03-11 15:49:55 +00:00
popa
2023-03-11 15:49:55 +00:00
ret
2023-03-13 12:40:28 +00:00
.error:
2023-03-18 06:42:18 +00:00
; Reset the disk system unconditionally, as we have no
2023-03-13 12:40:28 +00:00
; 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
2023-03-16 10:10:03 +00:00
; ------------------------------------------------------------------
; Filesystem
; ------------------------------------------------------------------
2023-03-18 13:55:53 +00:00
shell_name db 'shell.bin', 0
2023-03-16 10:10:03 +00:00
; in:
2023-03-16 15:52:41 +00:00
; ds:si = file name
2023-03-20 18:46:29 +00:00
; dx = non-zero => do not create new file
2023-03-16 10:10:03 +00:00
; out:
; ax = LBA of first sector, 0 if no space left or if dx non-zero and the
; specified file was not found
2023-03-16 10:10:03 +00:00
; cx = length in sectors
; di = dirent address (in GLOBAL_DIRENTS)
2023-03-19 17:28:30 +00:00
; [Far calls only]
2023-03-16 10:10:03 +00:00
open_file:
push si
push bx
2023-03-16 15:52:41 +00:00
push es
2023-03-16 10:10:03 +00:00
; Stolen from https://stackoverflow.com/a/72746473, get strlen (including
; null-termination) in cx
2023-03-16 15:52:41 +00:00
mov cx, ds
mov es, cx
2023-03-16 10:10:03 +00:00
mov di, si
mov cx, -1
xor ax, ax
repne scasb
not cx
2023-03-16 15:52:41 +00:00
mov es, ax
2023-03-16 10:10:03 +00:00
;mov ax, 1
mov al, 1
mov bx, GLOBAL_DIRENTS
2023-03-16 10:42:22 +00:00
xor di, di
call modify_sector
2023-03-16 10:10:03 +00:00
mov ax, 2
mov di, bx
.loop:
2023-03-16 15:52:41 +00:00
cmp word [es:di], 0
2023-03-16 10:10:03 +00:00
je .create_file
pusha
2023-03-16 10:10:03 +00:00
inc di
inc di
repe cmpsb
popa
2023-03-16 10:10:03 +00:00
je .success
2023-03-20 09:00:57 +00:00
add ax, FS_FILE_MAX_SIZE
add di, FS_DIRENT_SIZE
cmp di, GLOBAL_DIRENTS + 0x200
2023-03-16 10:10:03 +00:00
jl .loop
.error:
xor ax, ax
; Return with mangled cx, di
2023-03-16 10:10:03 +00:00
.success:
mov cx, [es:di]
2023-03-16 10:10:03 +00:00
.return:
2023-03-16 15:52:41 +00:00
pop es
2023-03-16 10:10:03 +00:00
pop bx
pop si
2023-03-19 17:28:30 +00:00
retf
2023-03-16 10:10:03 +00:00
.create_file:
test dx, dx
jnz .error
2023-03-16 10:10:03 +00:00
; TODO: zero out the sector for this file?
2023-03-16 15:52:41 +00:00
inc word [es:di]
pusha
2023-03-16 10:10:03 +00:00
inc di
inc di
rep movsb
2023-03-16 10:10:03 +00:00
mov ax, 1
;mov bx, GLOBAL_DIRENTS
2023-03-16 10:42:22 +00:00
mov di, 0x0100 ; write
call modify_sector
popa
jmp .success
2023-03-16 10:10:03 +00:00
2023-03-11 15:49:55 +00:00
; ------------------------------------------------------------------
; Mouse callback
; ------------------------------------------------------------------
2023-02-06 15:15:47 +00:00
Y_OVERFLOW equ 0x80
X_OVERFLOW equ 0x40
BUTTONS equ 0x03
2023-03-22 23:08:07 +00:00
X_MAX_VALUE equ (1 << X_SENSITIVITY)*COLUMNS-1
Y_MAX_VALUE equ (1 << Y_SENSITIVITY)*ROWS-1
2023-02-06 15:15:47 +00:00
; in:
; si = non-zero for Y
; di = &mouse_x/&mouse_y
; ax = X/Y
; bx = status
; cl = negative bit # in ah
; dx = MAX_VALUE
; zf = tested against overflow
; out
; [mouse_x]/[mouse_y] updated appropriately
; si = updated [mouse_x]/[mouse_y]
; di = di + 2
; clobbers ax
xy_handler:
jnz .overflow_return
; X and Y coördinates are stored as 9-bit signed integers
; using two's complement notation. The high bits are called
; "X negative" and "Y negative".
mov ah, bl
shl ah, cl ; Shift negative bit to sign position
sar ah, 7 ; Fill entire byte with sign bit's value
test si, si
jz .not_y
neg ax
.not_y:
mov si, [cs:di]
add si, ax
;cmp si, 0
jge .not_underflow
xor si, si
.not_underflow:
cmp si, dx
jle .not_overflow
mov si, dx
.not_overflow:
mov [cs:di], si
2023-03-20 18:50:22 +00:00
.overflow_return:
inc di
inc di
ret
2023-01-30 16:56:16 +00:00
mouse_handler:
pusha
2023-01-30 16:56:16 +00:00
2023-02-06 15:15:47 +00:00
mov bp, sp
2023-01-30 16:56:16 +00:00
2023-03-18 13:10:48 +00:00
mov bx, [bp+2*8+10] ; status
2023-02-06 15:15:47 +00:00
.x:
xor si, si
mov di, mouse_x
mov dx, X_MAX_VALUE
mov ax, [bp+2*8+8]
mov cl, 3
test bl, X_OVERFLOW
call xy_handler
2023-02-06 15:15:47 +00:00
.y:
inc si ; will be non-zero
mov ax, [bp+2*8+6]
mov cl, 2
2023-03-22 23:08:07 +00:00
mov dx, Y_MAX_VALUE
test bl, Y_OVERFLOW
call xy_handler
2023-03-20 18:48:46 +00:00
mov bh, 1 ; Mark that mouse state has updated
2023-02-06 15:15:47 +00:00
and bl, BUTTONS
2023-03-20 18:46:29 +00:00
mov [cs:di], bx
2023-03-20 18:18:49 +00:00
popa
2023-01-30 16:56:16 +00:00
retf
2023-03-11 15:49:55 +00:00
; ------------------------------------------------------------------
; Padding and boot sector signature
; ------------------------------------------------------------------
%ifndef SIZE
2022-02-11 16:16:49 +00:00
times 510-($-$$) db 0
%endif
2023-03-16 10:10:03 +00:00
2023-03-19 19:06:12 +00:00
memory_allocation_map:
2022-02-11 16:16:49 +00:00
db 0x55
db 0xaa
2023-02-06 15:15:47 +00:00
2023-03-11 15:49:55 +00:00
; ------------------------------------------------------------------
; Zero-initialized variables
; ------------------------------------------------------------------
2023-02-06 15:15:47 +00:00
section .bss
_bss_start:
2023-03-19 19:06:12 +00:00
resb 8 ; Rest of the memory allocation map
2023-02-06 15:15:47 +00:00
mouse_x resw 1
mouse_y resw 1 ; mouse_x + 2, do not touch
mouse_buttons resb 1 ; mouse_y + 2
2023-03-20 18:18:49 +00:00
mouse_change resb 1 ; mouse_buttons + 1
2023-02-06 15:15:47 +00:00
2023-02-06 16:02:21 +00:00
mouse_column resb 1
mouse_row resb 1 ; mouse_column + 1
2023-02-06 15:45:26 +00:00
2023-03-19 18:50:24 +00:00
window_chain_head resw 1
redraw resb 1
; Last thing in bss
2023-03-11 15:49:55 +00:00
boot_disk resb 1
_bss_end: