├── DOCS.TXT ├── INSTALL ├── Makefile ├── README.TXT ├── TODO ├── bfat12.asm ├── cstring.inc ├── debug.inc ├── fat12.inc ├── heap.inc ├── intrs.inc ├── kernel.asm ├── pseudogr.inc ├── shell.inc ├── stdio.inc ├── string.inc ├── sysdefs.inc ├── tetris.inc ├── time.inc ├── tmp.inc └── vga.inc /DOCS.TXT: -------------------------------------------------------------------------------- 1 | 2 | Welcome to DolphinOS! 3 | ver. 0.0.1 4 | 5 | "I'll build my own DOS! With blackjack 6 | and hookers!" 7 | - slightly paraphrased Bender 8 | 9 | Introduction 10 | DolphinOS is tiny and simplest operating system for x86 platform. Written 11 | for some assembler experience and lulz. 12 | 13 | Features: 14 | - bootloader for FAT12 file system; 15 | - monolithic kernel written in ASM (NASM used); 16 | - simplest shell; 17 | - single-user, single-task 16bit operating system; 18 | - support for FAT12 (under development); 19 | - memory handler (testing); 20 | 21 | Agenda: 22 | - support for fat32/vfat, ext2, iso9660 file systems; 23 | - loading user programs in .com format (ELF and PE later); 24 | - basic text editor; 25 | - basic VC/MC-like file manager; 26 | - basic graphics support; 27 | - valid unix-like shell; 28 | - ?????? 29 | - PROFIT!!! 30 | 31 | Kernel 32 | 33 | File systems 34 | File system hierarchy will be a single unix-like tree. There is a root, 35 | /, where traditional unix directories is located: /bin, /dev, /home. System 36 | disk is mounted to /, another devices - to mount points table entries. 37 | 38 | Heap 39 | Heap begins behind the kernel and has its own segment, whenever referred 40 | to pointer allocated with memalloc, it means HEAP_SEG:pointer. 41 | Heap segment is KERNEL_SEGM + kernel_end >> 4, adresses are 0x0000-0xffff 42 | Structure of heap: 43 | heap is build from chunks, each chunk contains header (4b) and arbitrary 44 | data after header: 45 | <----- chunk 0 -------> <- 1 -> <----- chunk 2 ---> ... 46 | |----|------------------|----|--|----|--------------| ... |----|--|0000| 47 | h1 data of h1 h2 data h3 data of h3 hN end 48 | where h1, h2, h3 - headers of chunks 49 | Header structure is: 50 | |--------|--------|---------|---------| 51 | <-- data length -> <- Serv-> <- CSum -> 52 | where data length - big-endian word, length of data after header 53 | Serv - service flags, this byte is 0, if chunk is free 54 | CSum - control sum, 55 | == high[datalentgh] + low[datalength] + low[datapointer] 56 | 57 | License 58 | Now it is BEERWARE: this source code provided AS IS. Author and owner 59 | does not take any responsibility for all misusage and data corruption caused 60 | by this product, but receives beer if it helped you :) 61 | 62 | Authors 63 | Currently product is developed and maintained by Dmytro Sirenko 64 | (email: dmytrish@gmail.com, jabber: EarlGray@jabber.kiev.ua, ICQ: 350799719). 65 | All constructive feedbacks and notes are welcomed. 66 | 67 | Special aknowledgements to: 68 | - NASM command for great development tool; 69 | - VIM for excellent code editor; 70 | - all music group I'm listening to during coding :) 71 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Compilation: 2 | for Unix-like system users: 3 | cd /path/to/dolphin 4 | make image boot kernel 5 | # if you want, you can write it to floppy: 6 | sudo dd if=dolphin.img of=/dev/fd0 7 | 8 | for Windows users: 9 | 1) compile kernel.asm with NASM with executable name KERNEL.BIN 10 | 2) copy it into the root of floppy disk 11 | 3) compile bootloader (bfat12.asm) into BOOT.BIN 12 | 4) write BOOT.BIN to the first sector of a floppy (with rawwrite.exe 13 | or whatever your Windoze's utility is); 14 | 15 | then boot from this floppy and enjoy! 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | BOOT=bfat12.asm 3 | KERN=kernel.asm 4 | KERNEL=KERNEL.BIN 5 | MBR_FILE=boot.mbr 6 | IMG_FILE=dolphin.img 7 | MNT_DIR=dolphin 8 | VBOX_OS=dolphin 9 | 10 | default:kernel run 11 | all: boot kernel run 12 | 13 | run: 14 | VirtualBox --startvm $(VBOX_OS) 15 | 16 | boot: 17 | nasm $(BOOT) -o $(MBR_FILE) 18 | dd if=$(MBR_FILE) of=$(IMG_FILE) conv=notrunc 19 | 20 | clean: 21 | rm $(KERN).lst || /bin/true 22 | rm $(KERNEL) || /bin/true 23 | rm $(MBR_FILE) || /bin/true 24 | rmdir $(MNT_DIR) 25 | 26 | image: 27 | dd if=/dev/zero of=$(IMG_FILE) bs=1k count=1440 28 | /sbin/mkfs.msdos -n DOLPHOS $(IMG_FILE) 29 | 30 | mount: 31 | if [ ! -x $(MNT_DIR) ] ; then mkdir $(MNT_DIR); \ 32 | else echo "Already mounted"; exit 0; fi 33 | sudo mount -t msdos -o loop $(IMG_FILE) $(MNT_DIR) || /bin/true 34 | echo "Mounted" 35 | 36 | umount: 37 | sudo umount $(MNT_DIR) 38 | rmdir $(MNT_DIR) 39 | 40 | dump: 41 | dd if=$(IMG_FILE) bs=1k count=10 | hexdump -C > $(IMG_FILE).hex 42 | 43 | kernel: 44 | nasm $(KERN) -o $(KERNEL) -l $(KERN).lst 45 | make mount 46 | sudo cp $(KERNEL) $(MNT_DIR) 47 | make umount 48 | -------------------------------------------------------------------------------- /README.TXT: -------------------------------------------------------------------------------- 1 | DolphinOS v0.01 2 | 3 | This version is the first working version of DOS-like OS with a valid shell. 4 | I wrote it studying intel assembler language and considering neither the system 5 | architecture and design, nor compatibility with existing systems, just extending 6 | bare bones with an every new feature I found in BIOS possibilities. 7 | There's a lot of dirty code and hacks, don't use it as a model. 8 | 9 | This version was written for a few weeks, starting with bootloader (3 days in 10 | Feb, 2010). 11 | 12 | Features: 13 | - FAT12 bootloader; 14 | - simplest shell with internal commands (type help to list it); 15 | - a lot of useless but nice features :) like neat clock at the screen and so on; 16 | - there is no memory manager, no disk driver, no filesystem; don't expect to 17 | encounter them :) 18 | 19 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | vga.inc: 3 | - arbitrary line drawing; 4 | - fucking tetris 5 | 6 | fat12.inc: 7 | - find_next/find_file 8 | - get_cluster_of_path 9 | - reading/changing directory 10 | - uploading entire file into memory 11 | - executing of loaded code 12 | - fopen/fclose 13 | 14 | shell.inc: 15 | - normal text commands 16 | - search for executable if prompt is not a command 17 | 18 | intrs.inc: 19 | - encapsulate func in interrupts 20 | - add tetris to interrupts 21 | = 22 | -------------------------------------------------------------------------------- /bfat12.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; this is bootloader for FAT12 (nasm) 3 | ; (c) Dmytro Sirenko, 04-06/04/2010 4 | ; Great thanks to ultimite boot-strap loader by Matthew Vea (VnutZ) 5 | ; This is beerware; 6 | ; you can copy, modify and steal it without any restrictions :) 7 | ; 8 | ; Notice: 9 | ; 1) if you read this code for learning, read FAT's spec. first! 10 | ; 2) terminology: boot2 means executable to load and jump to, it 11 | ; may be a kernel or a second-stage bootloader, see variable 12 | ; boot2 at the end of this file 13 | ; ___________________________________________________________________ 14 | 15 | USE_MEM equ 0x0200 ; place in memory for temp. data 16 | FAT_ENTRY_SIZE equ 0x0020 ; sizeof directory entry 17 | BOOT2_SEGM equ 0x0100 ; address in memory for boot2 18 | BOOT2_OFFS equ 0x0000 ; 19 | END_CLUSTER_MASK equ 0x0FF8 ; marker of last cluster for FAT12 20 | 21 | %define DEBUG 22 | %ifdef DEBUG 23 | %warning "_____________________warning: debug info included" 24 | %endif 25 | 26 | [bits 16] 27 | 28 | org 0x0000 ; where loader is to be found by bios 29 | 30 | entry: 31 | jmp short begin ; 0x0000 x0001; eb 3c 32 | 33 | ; ___________________________________________________________________ 34 | ; BIOS params block 35 | 36 | brINT13flag db 90h ; 0x0002 37 | brOEM db 'MSDOS5.0' 38 | brBPS dw 512 ; bytes per sector 39 | brSPC db 1 ; sectors/cluster 40 | brResCount dw 1 ; reserved sectors 41 | brFATs db 2 ; FAT copies 42 | brRootEntries dw 00e0h ; root directory entries 43 | brSectorCount dw 0B40h ; sector in volume 44 | brMedia db 0xF0 ; media descriptor 45 | brSPF dw 9 ; sector per FAT 46 | brSPH dw 18 ; sector per track 47 | brHPC dw 0x0002 ; number of heads 48 | brHidden dd 0 ; hidden sectors 49 | brSectors dd 0 ; [0x0020] 50 | brDriveNum db 0x00 ; phys. drive no 51 | brExtBootSig db 29h ; extended boot record sig 52 | brSerialNum dd 350518E3h 53 | brLabel db 'DolphinOS ' ; volume id, 11 chars 54 | brFSID db 'FAT12 ' ; fs id, 8 chars 55 | 56 | ; ___________________________________________________________________ 57 | ; 0x003E code 58 | begin: 59 | cli 60 | ; adjust code position 61 | mov ax, 0x07C0 ;; base of loader code, phys. addr = 0x07c00 62 | mov ds, ax 63 | mov es, ax 64 | mov fs, ax 65 | ; create stack 66 | xor ax, ax ;; stack at 0x0FFFF 67 | mov ss, ax 68 | mov sp, 0xFFFF 69 | sti 70 | 71 | mov si, welcome ;; says 'hello' 72 | call display_string 73 | 74 | ;; determine root directory size in sectors 75 | mov ax, word [brRootEntries] 76 | shl ax, 5 ; == * sizeof entry 77 | div word [brBPS] 78 | mov cx, ax ; count for dataSector 79 | 80 | ;; find sector of root directory 81 | mov ax, word [brSPF] 82 | mul byte [brFATs] 83 | add ax, word [brResCount] ; now ax - number of first root sector 84 | mov word [dataSector], ax 85 | add word [dataSector], cx 86 | ;; [dataSector] stores position of first Data (the last FAT part) sector 87 | 88 | ;; load root directory to memory at 07C0:0200 (behind the bootcode) 89 | mov bx, USE_MEM ; address to load to 90 | call LoadSectors 91 | jnc hang.ok 92 | read_fail: ;; display message: disk reading failed 93 | mov di, err_read_fail 94 | call display_string 95 | hang: jmp hang 96 | .ok: 97 | ;; now root directory is at 07c0:0200, search through it for boot2 98 | mov cx, word [brRootEntries] ; counter for loop 99 | mov di, USE_MEM ; where to begin. bx will be changing 100 | .next_root_entry: 101 | mov bx, 11 ; count of symbols to compare 102 | mov si, boot2 ; what with? 103 | ; compare 104 | push cx 105 | push di 106 | mov cx, 11 107 | rep cmpsb 108 | pop di 109 | pop cx 110 | je boot2_found 111 | 112 | add di, FAT_ENTRY_SIZE ; look up next entry 113 | loop .next_root_entry 114 | 115 | ; all root entries passed, no match 116 | mov si, boot2 117 | call display_string 118 | mov si, err_not_found 119 | call display_string 120 | jmp hang 121 | 122 | boot2_found: 123 | ;; di points to root dir entry for boot2 now 124 | mov dx, word [di + 0x001A] ; field "cluster" in entry structure 125 | mov word [cluster], dx 126 | 127 | ;; load the entire FAT into USE_MEM 128 | mov cx, word [brSPF] 129 | mov bx, USE_MEM 130 | mov ax, word [brResCount] 131 | call LoadSectors 132 | jc read_fail 133 | 134 | ;; prepare memory 135 | mov bx, BOOT2_SEGM ; kernel segment may change further 136 | mov es, bx 137 | mov bx, BOOT2_OFFS ; don't touch bx except memory handling! 138 | push bx 139 | 140 | .next_kernel_cluster: 141 | 142 | mov ax, word [cluster] 143 | call cluster_to_lba ; ax = LBA(cluster) 144 | xor cx, cx 145 | mov cl, byte [brSPC] ; read 1 cluster 146 | pop bx 147 | call LoadSectors ;; load ------------- 148 | ;; LoadSectors increments bx internally 149 | push bx 150 | jc read_fail 151 | 152 | ;; find next cluster 153 | mov ax, word [cluster] ; value of next cluster 154 | ; mul 3 155 | mov dx, ax 156 | shl ax, 1 157 | add ax, dx 158 | ; div 2 159 | shr ax, 1 160 | add ax, USE_MEM 161 | mov di, ax ; now di - offset of next cluster 162 | 163 | mov dx, word [di] ; read next cluster value 164 | ; dx - two bytes: 0xXCCC for even, 0xCCCX for odd cluster 165 | test byte [cluster], 0x01 ; check parity 166 | jnz .odd 167 | .even: 168 | and dx, 0x0FFF 169 | jmp short .enddif;ference :) 170 | .odd: 171 | shr dx, 4 172 | .enddif: 173 | mov word [cluster], dx 174 | 175 | ;; whether is the last 176 | cmp dx, END_CLUSTER_MASK 177 | jb .next_kernel_cluster ; last cluster of file is read 178 | 179 | ; premature optimization is the root of all evil, huh. 180 | ; an only needed sector in memory is good but the worse is better 181 | ;;;next_kernel_cluster: 182 | ;;; ;; echo 183 | ;;; push bx 184 | ;;; mov ax, 0x0E40 185 | ;;; mov bh, 0 186 | ;;; int 10h 187 | ;;; pop bx 188 | ;;; 189 | ;;; ;; what sectors do we need to load 190 | ;;; mov ax, word [cluster] 191 | ;;; call cluster_to_lba 192 | ;;; 193 | ;;; ;; load brSPC sectors of current cluster 194 | ;;; xor cx, cx 195 | ;;; mov cl, byte [brSPC] 196 | ;;; mov dx, cx ; save for next 197 | ;;; call LoadSectors 198 | ;;; 199 | ;;; ;; determine next position in memory 200 | ;;; mov ax, word [brBPS] 201 | ;;; mul dx ; bx += brSPC * brBPS 202 | ;;; jnc .this_seg ; overflow, need to read dx, more than 64 Kb 203 | ;;; mov di, es 204 | ;;; add di, dx 205 | ;;; mov es, di ; next segments 206 | ;;;.this_seg: 207 | ;;; add bx, ax 208 | ;;; 209 | ;;; ;; find next cluster of boot2 file 210 | ;;; ;; whether it was the last cluster of file 211 | ;;; mov ax, word [cluster] 212 | ;;; and ax, END_CLUSTER_MASK 213 | ;;; cmp ax, END_CLUSTER_MASK ; end cluster is 0xFF8-0xFFF 214 | ;;; je .done 215 | ;;; 216 | ;;; ;; search in FAT for the next cluster value 217 | ;;; ; determine necessary sector of FAT 218 | ;;; ; SectorNum = ResSectors + ((ClusterNum * 3)/2)/brBPS 219 | ;;; ; mem_offset = ((ClusterNum * 3)/2) % brBPS 220 | ;;; mov ax, word [cluster] 221 | ;;; ;mul 3: 222 | ;;; mov dx,ax; 223 | ;;; shl ax, 1 224 | ;;; add ax,dx ; wouldn't be better, i suppose 225 | ;;; shr ax, 1 226 | ;;; div word [brBPS] ; remainder is stored in dx 227 | ;;; add ax, word [brResCount] 228 | ;;; ; now ax - sector num, dx - offset 229 | ;;; cmp ax, word [fatSector] ; if is already loaded sector 230 | ;;; ; fatSector=0 for the first time, sector will be read 231 | ;;; je .already_loaded 232 | ;;; ;; read new sector 233 | ;;; mov word [fatSector], ax ; set new position 234 | ;;; push es 235 | ;;; push bx 236 | ;;; mov bx, ds 237 | ;;; mov es, bx 238 | ;;; mov bx, USE_MEM ; [es:bx] - int 13h reqirement 239 | ;;; call LoadSector 240 | ;;; pop es 241 | ;;; pop bx 242 | ;;;.already_loaded: 243 | ;;; ;; load next chain 244 | ;;; mov di, dx ; a [dx] call prohibited, [edx]/[di] only 245 | ;;; add di, USE_MEM 246 | ;;; mov cx, word [di] 247 | ;;; ; dx - offset, cx contains new 12bit cluster value now 248 | ;;; ; - like 0xXCCC (even) or 0xCCCX (odd) because of fucking 12bitness 249 | ;;; ; check a parity 250 | ;;; test byte [cluster], 0x01 251 | ;;; jnz .odd_cluster 252 | ;;;.even_cluster: 253 | ;;; and cx, 0x0FFF ; 0xXCCC & 0x0FFF = 0x0CCC 254 | ;;; jmp short .no_difference 255 | ;;;.odd_cluster: 256 | ;;; shr cx, 0x04 ; 0xCCCX >> 4 = 0x0CCC 257 | ;;;.no_difference: 258 | ;;; ; now cx - cluster number 259 | ;;; mov word [cluster], cx 260 | ;;; jmp next_kernel_cluster 261 | 262 | 263 | ;; memory look up 264 | ;;;%ifdef DEBUG 265 | ;;; mov dl, 'd' ; "d"one 266 | ;;; call display_char 267 | ;;; ;; debug: what is in memory? 268 | ;;; mov bx, BOOT2_OFFS 269 | ;;;.rep: 270 | ;;; mov dx, [es:bx] 271 | ;;; ;; hex output of dx 272 | ;;; mov cx, 4 273 | ;;;.for: 274 | ;;; mov dl, ah 275 | ;;; shr dl, 4 276 | ;;; ; convert to ascii 277 | ;;; cmp dl, 0x0A 278 | ;;; jl .dec 279 | ;;; add dl, 7 ; abcdef: 'A' - 10 - '0' 280 | ;;;.dec: add dl, 0x30 281 | ;;; call display_char 282 | ;;; shl ax, 4 283 | ;;; loop .for 284 | ;;; ;; next word 285 | ;;; add bx, 0x0002 286 | ;;; cmp bx, 0x0200 287 | ;;; jne .rep 288 | ;;;%endif 289 | 290 | ;; jump to destination at last :) 291 | push word BOOT2_SEGM 292 | push word BOOT2_OFFS 293 | retf 294 | 295 | ; ___________________________________________________________________ 296 | LoadSector: 297 | ; loads 1 sector at FAT's [ax] (LBA address) into memory at [es:bx]. 298 | ; doesn't preserve cx, dx 299 | ; out: cf = 0, loaded sector in [es:bx] if ok, cf = 1 otherwise 300 | 301 | mov di, 5 ; retries 5 times, due to hardware reasons 302 | .effort: 303 | push bx 304 | push ax 305 | call lba_to_chs 306 | mov ax, 0x0201 ; ah = 02h - BIOS func for int 13h: read sector 307 | ; al = 01h, just an only sector 308 | mov ch, byte [absTrack] 309 | mov cl, byte [absSector] 310 | mov dh, byte [absHead] 311 | mov dl, byte [brDriveNum] 312 | int 13h 313 | test al, al 314 | jz .fail 315 | pop ax 316 | pop bx 317 | jnc .ok ; load ok? 318 | 319 | ; next effort 320 | .fail: push ax 321 | xor ax, ax ; int 13h, AH=0 322 | int 13h ; reset disk 323 | 324 | pop ax 325 | dec di 326 | jnz .effort ; try again 327 | stc 328 | .ok: 329 | retn 330 | 331 | ; ___________________________________________________________________ 332 | LoadSectors: 333 | ; loads cx sectors beginning at ax to memory at es:bx 334 | ; args: ax - address of first sector, 335 | ; bx - memory address to load to, 336 | ; cx - count of sectors 337 | ; out: 338 | read_sector: ; loop for sectors, 1 per time 339 | push cx 340 | push bx 341 | call LoadSector 342 | %ifdef DEBUG 343 | mov dl, '.' 344 | call display_char 345 | %endif 346 | jnc load_ok 347 | pop bx 348 | pop cx 349 | jmp ls_ret 350 | 351 | load_ok: 352 | pop bx 353 | pop cx 354 | add bx, word [brBPS] ; next position in buffer 355 | inc ax ; next sector 356 | loop read_sector ; read next sector 357 | 358 | ls_ret: 359 | %ifdef DEBUG 360 | mov dl, 10 361 | call display_char 362 | mov dl, 13 363 | call display_char 364 | %endif 365 | retn 366 | 367 | ; ___________________________________________________________________ 368 | cluster_to_lba: 369 | ; converts fat cluster number to lba pointer 370 | ; LBA = (cluster - 2) * sectors per cluster 371 | ; args: ax - cluster 372 | ; out: ax - lba 373 | sub al, 0x02 374 | xor cx, cx 375 | mov cl, byte [brSPC] 376 | mul cx 377 | add ax, word [dataSector] 378 | retn 379 | 380 | ; ___________________________________________________________________ 381 | lba_to_chs: 382 | ; converts LBA sector number to CHS 383 | ; absSector = (logicalSector / sectors_per_track ) + 1 384 | ; absHead = (logicalSector / sectors_per_track ) mod number_of_heads 385 | ; absTrack = logicalSector / (sectors_per_track * number_of_heads) 386 | ; args: ax - logical sector number 387 | ; out: absSector, absHead, absTrack 388 | xor dx, dx 389 | div word [brSPH] ; ax = ax / brSPH 390 | inc dl ; dx - absSector 391 | mov byte [absSector], dl 392 | xor dx, dx 393 | div word [brHPC] 394 | mov byte [absHead], dl 395 | mov byte [absTrack], al 396 | retn 397 | 398 | %ifdef DEBUG 399 | ; ___________________________________________________________________ 400 | display_char: 401 | ; dl - ASCII 402 | push ax 403 | push bx 404 | mov al, dl 405 | mov ah, 0x0E 406 | mov bx, 0x0007 407 | int 0x10 408 | pop bx 409 | pop ax 410 | retn 411 | %endif 412 | 413 | ; ___________________________________________________________________ 414 | display_string: 415 | ; just put an ASCIIZ string [ds:si] on display using BIOS 416 | lodsb ; al = [ds:si] 417 | test al, al ; set zero flag if al = 0 418 | jz .ret 419 | mov ah, 0x0E ; video func 0E 420 | mov bx, 0x0007 ; color 421 | int 0x10 422 | jmp display_string 423 | .ret: retn 424 | 425 | ; ___________________________________________________________________ 426 | ; DATA 427 | ; 428 | welcome db 'DolphinOS bootloader', 13, 10, 0 429 | err_read_fail db "Read failure", 0 430 | err_not_found db " not found", 0 431 | boot2 db "KERNEL BIN" ; 11 bytes 432 | 433 | fatSector dw 0x0000 434 | cluster dw 0x0000 435 | dataSector dw 0x0000 436 | 437 | absSector db 0x00 438 | absHead db 0x00 439 | absTrack db 0x00 440 | 441 | size equ $ - entry 442 | %if size > 510 443 | %error "code is too large" 444 | %endif 445 | times (512 - size - 2) db 0 446 | db 0x55, 0xAA ; boot signature 447 | -------------------------------------------------------------------------------- /cstring.inc: -------------------------------------------------------------------------------- 1 | %ifndef __CSTRING_INC__ 2 | %define __CSTRING_INC__ 3 | 4 | ; ___________________________________________________________________ 5 | strcmp: 6 | ; compare bx symbols at [ds:si] with [es:di] 7 | ; out : set zf if equal 8 | push di 9 | inc bx 10 | cmp_iter: 11 | dec bx 12 | jz cmp_ret 13 | cmpsb 14 | je cmp_iter ; it's a kind of magic, nyah 15 | cmp_ret: 16 | pop di 17 | retf 18 | 19 | ; ___________________________________________________________________ 20 | strncmp: 21 | ;// zf strncmp(ds:si str1, es:di str2, cx n) 22 | rep cmpsb 23 | retf 24 | 25 | 26 | %endif 27 | -------------------------------------------------------------------------------- /debug.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Some debug routines 3 | ; (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | 6 | %ifndef __DEBUG_INC__ 7 | %define __DEBUG_INC__ 8 | 9 | %include "pseudogr.inc" 10 | 11 | ; 12 | dbg_print_char_dl: 13 | ; args: dl - ASCII 14 | ; out: none 15 | ; preserves all fags 16 | pusha 17 | pushf 18 | mov ah, 0x0E 19 | mov bx, 0x0007 20 | mov al, dl 21 | int 10h 22 | popf 23 | popa 24 | retn 25 | 26 | ; 27 | dbg_print_hex_dl: 28 | pusha 29 | pushf 30 | mov ah, 0x0E 31 | mov bx, 0x0007 32 | mov al, dl 33 | shr al, 4 34 | cmp al, 10 35 | jl .dec 36 | add al, 'A' - '9' - 1 37 | .dec: add al, '0' 38 | int 10h 39 | mov al, dl 40 | and al, 0x0F 41 | cmp al, 10 42 | jl .dec2 43 | add al, 'A' - '9' - 1 44 | .dec2: add al, '0' 45 | int 10h 46 | mov al, ' ' 47 | call out_char 48 | 49 | popf 50 | popa 51 | retn 52 | ; 53 | dbg_print_word_dx: 54 | ; args: 55 | ; dx - word 56 | ; out: none 57 | ; preserves all flags 58 | pusha 59 | pushf 60 | 61 | mov ah, 0x0E 62 | mov bx, 0x0007 63 | 64 | mov cx, 0x0004 65 | .loop: 66 | mov al, dh 67 | shr al, 4 ; al = digit 68 | ; convert to ascii 69 | cmp al, 10 70 | jl .dec 71 | add al, 'A' - '9' - 1 72 | .dec: add al, '0' 73 | int 10h 74 | 75 | shl dx, 4 76 | loop .loop 77 | mov al, ' ' 78 | int 10h 79 | 80 | popf 81 | popa 82 | retn 83 | 84 | ; 85 | dbg_print_string: 86 | pusha 87 | pushf 88 | mov ah, 0x0E 89 | mov bx, 0x0007 90 | .iter: 91 | mov al, [si] 92 | and al, al 93 | jz .done 94 | int 0x10 95 | lodsb 96 | jmp .iter 97 | .done: 98 | popf 99 | popa 100 | retn 101 | 102 | ; 103 | dbg_dump_mem: 104 | ; hex output of memory at [es:di] to [es:di+cx] 105 | ; 106 | pusha 107 | pushf 108 | xor bx, bx 109 | mov al, 1 110 | .loop: dec al 111 | jnz .next 112 | mov al, 0x10 113 | mov dl, 13 114 | call dbg_print_char_dl 115 | mov dl, 10 116 | call dbg_print_char_dl 117 | .next: mov dl, byte [es : di+bx] 118 | call dbg_print_hex_dl 119 | inc bx 120 | loop .loop 121 | 122 | popf 123 | popa 124 | retn 125 | .endl db 13, 10, 0 126 | 127 | ;; __________________________________________________________________ 128 | dbg_hex_input_dx: 129 | ;; args: none 130 | ;; rets: dx - word 131 | pusha 132 | xor dx, dx 133 | xor cl, cl 134 | .loop: 135 | push dx 136 | call get_char 137 | pop dx 138 | 139 | cmp cl, 4 140 | jge .no_digit 141 | 142 | cmp al, '0' 143 | jl .is_A_F 144 | cmp al, '9' 145 | jg .is_A_F 146 | call out_char 147 | sub al, '0' 148 | jmp .digit 149 | .is_A_F: 150 | cmp al, 'A' 151 | jl .is_a_f 152 | cmp al, 'F' 153 | jg .is_a_f 154 | call out_char 155 | sub al, 'A' - 10 156 | jmp .digit 157 | .is_a_f: 158 | cmp al, 'a' 159 | jl .no_digit 160 | cmp al, 'f' 161 | jg .no_digit 162 | call out_char 163 | sub al, 'a' - 10 164 | jmp .digit 165 | .no_digit: 166 | cmp al, 13 ;; enter? 167 | je .break 168 | cmp al, 8 ;; bksp? 169 | jne .loop 170 | test cl, cl 171 | jle .loop 172 | dec cl 173 | ;; clear last symbol 174 | mov si, clsymb 175 | call display_string 176 | ;; dlete it from dx 177 | shr dx, 4 178 | jmp .loop 179 | .digit: 180 | shl dx, 4 181 | inc cl 182 | add dl, al 183 | jmp .loop 184 | .break: 185 | mov si, endl 186 | call display_string 187 | mov word[.res], dx 188 | popa 189 | mov dx, word[.res] 190 | retn 191 | .res dw 0x0000 192 | 193 | 194 | %macro SHOW_SEGREG 1 195 | mov si, dbg_seg_regs.s_%1 196 | call display_string 197 | mov al, '=' 198 | call out_char 199 | 200 | mov dx, %1 201 | call dbg_print_word_dx 202 | mov al, ' ' 203 | call out_char 204 | %endmacro 205 | ;; __________________________________________________________________ 206 | dbg_window_cpu: 207 | ;;; 208 | 209 | REG_STR_LENGTH equ 3 210 | 211 | pusha 212 | 213 | ;; adrress where this function called from 214 | mov si, .caller 215 | call display_string 216 | mov si, sp 217 | add si, 16 218 | mov dx, [ss : si] 219 | call dbg_print_word_dx 220 | mov si, endl 221 | call display_string 222 | 223 | ;; general registers 224 | mov cx, 8 225 | mov di, dbg_regs 226 | .next_reg: 227 | mov ax, cx 228 | dec ax 229 | mov bl, 0x03 230 | mul bl 231 | mov si, di 232 | add si, ax 233 | call display_string 234 | 235 | mov al, '=' 236 | call out_char 237 | 238 | mov si, sp 239 | ;inc si ;; cause of flags 240 | mov bx, cx 241 | dec bx 242 | shl bx, 1 243 | add si, bx ;; offset 244 | mov dx, word [ss : si] 245 | call dbg_print_word_dx 246 | 247 | mov al, ' ' 248 | call out_char 249 | loop .next_reg 250 | 251 | mov si, endl 252 | call display_string 253 | ;; segment registers 254 | SHOW_SEGREG ds 255 | SHOW_SEGREG es 256 | SHOW_SEGREG fs 257 | SHOW_SEGREG gs 258 | SHOW_SEGREG ss 259 | SHOW_SEGREG cs 260 | 261 | ;popf 262 | popa 263 | retn 264 | .caller db "Called from ", 0 265 | dbg_regs: 266 | .s_di db "DI", 0 267 | .s_si db "SI", 0 268 | .s_bp db "BP", 0 269 | .s_sp db "SP", 0 270 | 271 | .s_bx db "BX", 0 272 | .s_dx db "DX", 0 273 | .s_cx db "CX", 0 274 | .s_ax db "AX", 0 275 | 276 | dbg_seg_regs: 277 | .s_ds db "DS", 0 278 | .s_es db "ES", 0 279 | .s_fs db "FS", 0 280 | .s_gs db "GS", 0 281 | 282 | .s_cs db "CS", 0 283 | .s_ss db "SS", 0 284 | .s_ip db "IP", 0 285 | 286 | .s_flags db "FLAGS", 0 287 | 288 | 289 | %endif 290 | -------------------------------------------------------------------------------- /fat12.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains routines for handling FAT12/16 filesystems 3 | ; (c) Dmytro Sirenko, 2010 4 | ; ___________________________________________________________________ 5 | ; Unit description 6 | ; Interface; 7 | ; fmount_fat12 : - reads needed data for fat12 filesystem 8 | ; fopen_fat12 9 | ; 10 | ; =================================================================== 11 | 12 | %ifndef __FAT12 13 | %define __FAT12 14 | 15 | %include "sysdefs.inc" 16 | %include "stdio.inc" 17 | %include "debug.inc" 18 | 19 | [segment .data] 20 | 21 | ;;; Global FAT data 22 | ;;; _________________________________________________________________ 23 | ;; _____ BIOS parameter block _____________________________ 24 | bpb: 25 | .oem_name times 8 db 0x00 ; oem name, 8 chars 0x00 26 | .BpS dw 0x0000 ; bytes per sector 0x08 27 | .SpC db 0x00 ; sectors per cluster 0x0A 28 | .reserved dw 1 ; reserved sectors count 0x0B 29 | .FATs db 2 ; count of FAT copies 0x0D 30 | .rtentr dw 0x0000 ; count of root entries 0x0E 31 | .ttl_sctrs dw 0x0000 ; total sectors count 0x10 32 | .type db 0xF0 ; media type 0x12 33 | .SpF dw 0x0000 ; sectors per FAT 0x13 34 | .SpH dw 0x0000 ; sectors per head 0x15 35 | .HpC dw 0x0000 ; number of heads 0x17 36 | .hddn_sctrs dd 0 ; hidden sectors 0x19 37 | .ttl_sctrs32 dd 0 ; 32bit ttl_sctrs count 0x1D 38 | 39 | sizeof_bpb equ $ - bpb ; 0x21 40 | 41 | ;; _____ Extended bpb for FAT12/16 _____________________ 42 | ebpb1x: 43 | .drive_num db 0 ; phys. drive number 44 | .ext_boot_sig db 0x00 ; signature of three foll. fields 45 | .serial dd 0 ; serial number of device 46 | .label times 11 db 0x00 ; volume id, 11 chars 47 | .fs_id times 8 db 0x00 ; fs id, 8 chars 48 | 49 | sizeof_ebpb equ $ - ebpb1x 50 | 51 | ;;;; _____ Extended bpb for FAT32 _____________________ 52 | 53 | ;; _____________ FAT entry _____________________ 54 | SIZEOF_FAT_ENTRY equ 20 55 | 56 | ;;; temporarily!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 57 | fopen equ fopen_fat12 58 | fclose equ fclose_fat12 59 | fmount equ fmount_fat12 60 | fread equ fread_fat12 61 | 62 | chs: 63 | .track db 0x00 64 | .head db 0x00 65 | .sector db 0x00 66 | 67 | rootSector dw 0x0000 68 | dataSector dw 0x0000 69 | 70 | ; _________ messages ______________________________________________ 71 | fat_welcome db "Mounting FAT...", 10, 13, 0 72 | err_fat_missing db 13, "Error: FAT12 header is missing", 10, 13, 0 73 | 74 | 75 | [segment .text] 76 | ;;; ;;;;;;;;;;; Unit Interface ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 77 | ;;; _________________________________________________________________ 78 | fmount_fat12: 79 | ;;;// __far void fmount_fat12(void) 80 | ;;; initializes: fs type, cluster size and so on 81 | ;;; args: 82 | 83 | mov si, fat_welcome 84 | call display_string 85 | 86 | ;; copy data to bpb 87 | push ds ; save ds 88 | ; from: 89 | push BOOT_SEG 90 | pop ds 91 | 92 | mov cx, sizeof_bpb ; count 93 | mov si, BOOT_MEM + 3 94 | ; bpb structure beginning is located at byte 0x03 in 0th sector 95 | ; to: 96 | ; mov es, KERNEL_SEGM - is set already 97 | mov di, bpb ; offset 98 | call KERNEL_SEGM:memcopy 99 | 100 | mov cx, sizeof_ebpb 101 | mov si, BOOT_MEM + 3 + sizeof_bpb 102 | mov di, ebpb1x 103 | call KERNEL_SEGM:memcopy 104 | 105 | pop ds ; restore ds 106 | 107 | 108 | mov dx, [bpb.BpS] 109 | call dbg_print_word_dx 110 | 111 | ;; calculate dataSector 112 | ; dataSector = reserved + fat_count * SpF + 113 | ; + (root_entr_count * 20h)/BpS; 114 | movzx ax, byte [bpb.FATs] 115 | mul word [bpb.SpF] 116 | add ax, [bpb.reserved] 117 | mov word [rootSector], ax 118 | mov dx, ax 119 | 120 | ; root size 121 | mov ax, [bpb.rtentr] 122 | shl ax, 5 ; == mul 20h == mul sizeof(entry) 123 | div word [bpb.BpS] 124 | add dx, ax 125 | mov word [dataSector], dx 126 | 127 | call dbg_print_word_dx 128 | 129 | ;; init cache 130 | call cache_init 131 | 132 | retn ; can be called from anywhere, so far ret 133 | 134 | ;; __________________________________________________________________ 135 | cache_init: 136 | xor ax, ax 137 | push es 138 | push word [cache_seg] 139 | pop es 140 | mov [es:0000], ax 141 | mov [es:0002], ax 142 | pop es 143 | retn 144 | 145 | ;;; _________________________________________________________________ 146 | fopen_fat12: 147 | ;;; args: 148 | ;;; ds:si - file name 149 | ;;; al - flags (E_READ | E_WRITE | E_APPEND) 150 | ;;; out: 151 | ;;; ax - file descriptor, 0 if failed, errcode in bx 152 | ;;; 153 | ;; find file 154 | ; parse path 155 | 156 | 157 | ;; 158 | 159 | retn 160 | 161 | ;;; _________________________________________________________________ 162 | fclose_fat12: 163 | retn 164 | 165 | ;;; _________________________________________________________________ 166 | fread_fat12: 167 | retn 168 | 169 | 170 | ; ___________________________________________________________________ 171 | print_fat_entry: 172 | ;; void print_fat_entry(bx *entry) 173 | ;mov si, .endl 174 | ;call display_string 175 | mov di, 0 176 | .name_loop: 177 | mov al, byte [bx + di] 178 | cmp al, ' ' 179 | je .end_loop 180 | call out_char 181 | inc di 182 | cmp di, 8 183 | jl .name_loop 184 | .end_loop: 185 | cmp byte [bx + 8], ' ' 186 | je .no_ext 187 | mov al, '.' 188 | call out_char 189 | 190 | mov di, 0 191 | .ext_loop: 192 | mov al, byte [bx + di + 8] 193 | cmp al, ' ' 194 | je .no_ext 195 | call out_char 196 | inc di 197 | cmp di, 3 198 | jl .ext_loop 199 | .no_ext: 200 | retn 201 | 202 | ;; __________________________________________________________________ 203 | cache_file: 204 | ;; 205 | retn 206 | 207 | ;; __________________________________________________________________ 208 | cache_cluster: 209 | ;; args: 210 | ;; ax - number of cluster to be cached 211 | ;; out: 212 | ;; CACHE_SEG:bx - adrress of mem image 213 | 214 | retn 215 | 216 | ;; __________________________________________________________________ 217 | cache_sectors: 218 | ;; args: 219 | ;; ax - number of first sector to be cached 220 | ;; cx - count of sectors 221 | ;; rets: 222 | ;; [cache_seg]:bx - address of mem image 223 | ;;; 224 | push ax 225 | push cx 226 | call get_sector_cache 227 | 228 | pop cx 229 | pop ax 230 | test bx, bx 231 | jnz .ret ;; already loaded 232 | ;;; we have to load it 233 | ;;; find a place for cache 234 | call get_place_for_cache 235 | ;; now bx - place for sector 236 | push es 237 | 238 | .load_sector: 239 | call _read_sector 240 | add bx, word [bpb.BpS] 241 | inc ax 242 | loop .load_sector 243 | pop es 244 | .ret: retn 245 | 246 | 247 | ;;; _________________________________________________________________ 248 | get_place_for_cache: 249 | ;; args: 250 | ;; ax - count of sectors 251 | ;; rets: 252 | ;; bx - pointer to place 253 | 254 | push es 255 | mov bx, word [cache_seg] 256 | mov es, bx 257 | mov bx, SIZEOF_CACHE_HEADER 258 | push ax 259 | .find_cache: 260 | mov dx, word [es: bx-4] 261 | test dx, dx 262 | jz .found 263 | movzx ax, byte [es: bx-2] 264 | mul word [bpb.BpS] 265 | add bx, ax 266 | add bx, SIZEOF_CACHE_HEADER 267 | jmp .find_cache 268 | .found: ;; is there enough space for new cache? 269 | pop ax 270 | ; is CACHE_SIZE - 4 - bx > cx * BpS? 271 | push ax 272 | mov ax, cx 273 | mul word [bpb.BpS] 274 | push bx 275 | sub bx, CACHE_SIZE - 4 276 | neg bx 277 | cmp bx, ax 278 | pop ax 279 | jge .enough 280 | call cache_init 281 | ;; go to first cache entry 282 | mov bx, SIZEOF_CACHE_HEADER 283 | .enough:pop es 284 | retn 285 | 286 | ;;; Cache: 287 | ;;; |--|-----------------|--|--------|00|00000... 288 | ;;; d1 sector cache 1 d2 cache2 end of cache - 289 | ;;; d1, d2 - descriptors zero descriptor 290 | ;; v 291 | ;; |-----|----------|-----------|------------| 292 | ;; cache sect0 sect1 ^ sect2 293 | ;; descr<-------- cx --------->bx 294 | ;; cache desriptor: 295 | ;; |--------|--------|--------|--------| 296 | ;; <--- 1stSecNum -> <------> <------> 297 | ;; SC CS 298 | ;; SC - sectors count after 1st 299 | ;; CS - Check sum 300 | 301 | 302 | ;; __________________________________________________________________ 303 | get_sector_cache: 304 | ;; args: 305 | ;; ax - sector 306 | ;; rets: 307 | ;; CACHE_SEG:bx - pointer, 0 if not found (first cache lays at 0x0004) 308 | ;; cx - number of this sector in the cache sequence 309 | SIZEOF_CACHE_HEADER equ 4 310 | push es 311 | push word [cache_seg] 312 | pop es 313 | mov bx, SIZEOF_CACHE_HEADER 314 | .next_cache: 315 | mov cx, word [es: bx - 4] 316 | test cx, cx 317 | jz .endofcache ;; 0th sector is never cached, cache ends with 0 318 | movzx dx, byte [es: bx - 2] 319 | cmp ax, cx 320 | jl .not_this ;; cache contains older sectors than one being searching for 321 | add dx, cx 322 | cmp ax, dx 323 | jge .not_this ;; given sector is older than ones in cache 324 | ;; yes, this cache contains sought sector 325 | sub ax, cx 326 | mov cx, ax ;; cx - number of this sector in cached sequence 327 | jmp .ret 328 | .not_this: 329 | ;; go to next cache 330 | push ax 331 | movzx ax, byte [es : bx - 2] 332 | mul word [bpb.BpS] 333 | add bx, ax 334 | add bx, SIZEOF_CACHE_HEADER 335 | ;; cache must end with zero descriptor, so don't check the end of cache memory 336 | pop ax 337 | jnz .next_cache 338 | .endofcache: 339 | ;; sector not found 340 | xor bx, bx 341 | .ret: pop es 342 | retn 343 | ;; 344 | ; ___________________________________________________________________ 345 | get_path_cluster: 346 | ;// ax get_path_cluster(ds:si dir_path) 347 | 348 | retn 349 | 350 | ; ___________________________________________________________________ 351 | get_first_cluster: 352 | ;// ax get_first_cluster(ds:si name, ax dir_cluster) 353 | ; 354 | DIR_MEM equ ((CACHE_SIZE << 4) - 0x300) 355 | test ax, ax 356 | jnz .datapart 357 | ;; root dir 358 | mov ax, word [rootSector] 359 | .datapart: 360 | ;; 361 | push es 362 | mov di, word [cache_seg] 363 | mov es, di 364 | mov bx, DIR_MEM 365 | call _cluster_to_sector 366 | movzx cx, [bpb.SpC] 367 | call upload_sectors 368 | pop es 369 | ;; 370 | 371 | retn 372 | 373 | 374 | ; ___________________________________________________________________ 375 | get_next_cluster: 376 | ;; ax get_next_cluster(ax cluster) 377 | 378 | retn 379 | 380 | ; ___________________________________________________________________ 381 | find_file_fat12: 382 | ;; args: 383 | ;; ax - dir_cluster, 0 if root 384 | ;; ds:si - name (11) 385 | ;; out dx - pointer to entry where to copy file info (20h bytes) 386 | ;; 0 if not found 387 | pusha 388 | mov word [.dir_cluster], ax 389 | jz .root 390 | ;; read directory: 391 | jmp .ret 392 | .root: ;; read root: 393 | mov cx, [bpb.rtentr] 394 | mov bx, 0h 395 | .next_rootentry: 396 | cmp bx, word [bpb.BpS] 397 | jl .no_load 398 | .no_load: 399 | add bx, SIZEOF_FAT_ENTRY 400 | loop .next_rootentry 401 | ;; not found 402 | xor dx, dx 403 | 404 | .ret: popa 405 | retn 406 | .dir_cluster dw 0x0000 407 | 408 | ; ___________________________________________________________________ 409 | fat12_internal_name: 410 | ;; returns e.g. "KERNEL BIN" (11 chars) from "Kernel.bin",0 411 | ;; redundant symbols (>8th for name and >3 for ext) are ignored 412 | ;; spaces is always padding! 413 | ;; args: 414 | ;; ds:si - pointer to usual name 415 | ;; ds:bx - pointer to 11 bytes buffer 416 | ;; TODO: do it!! 417 | pusha 418 | mov cx, 8 419 | .next_name_symb: 420 | mov al, byte [si] 421 | ;; check whether is valid 422 | test al, 0x80 423 | jnz .valid_symb 424 | ;bt fat12_valid_symbs, al 425 | jnc .invalid_symb 426 | .valid_symb: 427 | ;; valid 428 | ;; transform to uppercase if needed 429 | mov byte [bx], al 430 | 431 | loop .next_name_symb 432 | .invalid_symb: 433 | cmp al, '.' 434 | je .ext 435 | cmp al, 0 436 | jne .invfname 437 | 438 | .ext: 439 | 440 | .invfname: 441 | popa 442 | mov ax, E_INVALID_FILE_NAME 443 | retn 444 | .ok: 445 | popa 446 | mov ax, NO_ERROR 447 | retn 448 | ;; bitfield for valid ascii (0-127) symbols in fat names 449 | fat12_valid_symbs db 0x00, 0x00, 0x00, 0x00, 0x6F, 0xC4, \ 450 | 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE3, \ 451 | 0xFF, 0xFF, 0xFF, 0xF6 452 | 453 | ; ___________________________________________________________________ 454 | upload_sectors: 455 | ;; args: 456 | ;; ax - lba address of first sector 457 | ;; es:bx - pointer where to load 458 | ;; cx - count 459 | ;; outs: 460 | ;; cf = 0 if success 461 | ;; changes bx, ax, cx 462 | 463 | .next_sector: 464 | call _read_sector 465 | jc .ret 466 | inc ax 467 | add bx, word [bpb.BpS] 468 | loop .next_sector 469 | .ret retn 470 | 471 | ; ___________________________________________________________________ 472 | upload_file: 473 | ;; args: 474 | ;; ds:si - string of file name 475 | ;; es:di - memory to load in 476 | ;; ax - cluster of directory, 0 for root 477 | ;; outs: 478 | ;; cf = 0 if success 479 | 480 | call get_first_cluster 481 | 482 | mov bx, di 483 | .next_cluster: 484 | ;; load cluster 485 | push ax 486 | call _cluster_to_sector 487 | movzx cx, byte [bpb.SpC] 488 | call upload_sectors 489 | jc .ret 490 | pop ax 491 | ;; last? 492 | cmp ax, 0x0FF8 493 | jge .ret 494 | ;; find next 495 | call get_next_cluster 496 | jmp .next_cluster 497 | .ret: retn 498 | 499 | ; ___________________________________________________________________ 500 | _cluster_to_sector: 501 | _cluster_to_lba: 502 | ; converts fat cluster number to lba pointer 503 | ; LBA = (cluster - 2) * sectors per cluster 504 | ; args: ax - cluster 505 | ; out: ax - lba 506 | ;// ax _cluster_to_sector(ax cluster) 507 | sub al, 0x02 508 | xor cx, cx 509 | mov cl, byte [bpb.SpC] 510 | mul cx 511 | add ax, word [dataSector] 512 | retn 513 | 514 | ; ___________________________________________________________________ 515 | _lba_to_chs: 516 | ; converts LBA sector number to CHS 517 | ; absSector = (logicalSector / sectors_per_track ) + 1 518 | ; absHead = (logicalSector / sectors_per_track ) mod number_of_heads 519 | ; absTrack = logicalSector / (sectors_per_track * number_of_heads) 520 | ; args: ax - logical sector number 521 | ; out: chs 522 | xor dx, dx 523 | div word [bpb.SpH] ; ax = ax / brSPH 524 | inc dl ; dx - absSector 525 | mov byte [chs.sector], dl 526 | xor dx, dx 527 | div word [bpb.HpC] 528 | mov byte [chs.head], dl 529 | mov byte [chs.track], al 530 | retn 531 | 532 | ; ___________________________________________________________________ 533 | _read_sector: 534 | ; loads 1 sector at FAT's [ax] (LBA address) into memory at [es:bx]. 535 | ; out: cf = 0, loaded sector in [es:bx] if ok, cf = 1 otherwise 536 | ; preserves all registers 537 | pusha 538 | mov di, 5 ; retries 5 times, due to hardware reasons 539 | .effort: 540 | push bx 541 | push ax 542 | call _lba_to_chs 543 | mov ax, 0x0201 ; ah = 02h - BIOS func for int 13h: read sector 544 | ; al = 01h, just 1 545 | mov ch, byte [chs.track] 546 | mov cl, byte [chs.sector] 547 | mov dh, byte [chs.head] 548 | mov dl, byte [ebpb1x.drive_num] 549 | int 13h 550 | test al, al 551 | jz .fail 552 | pop ax 553 | pop bx 554 | jnc .ok ; load ok? 555 | 556 | ; next effort 557 | .fail: push ax 558 | xor ax, ax ; int 13h, AH=0 559 | int 13h ; reset disk 560 | 561 | pop ax 562 | dec di 563 | jnz .effort ; try again 564 | stc 565 | .ok: popa 566 | retn 567 | 568 | %endif 569 | -------------------------------------------------------------------------------- /heap.inc: -------------------------------------------------------------------------------- 1 | ;;; 2 | ;;; DolphinOS (c) Dmytro Sirenko 3 | ;;; Memory handling routines 4 | ;;; _________________________________________________________________ 5 | ;;; ================================================================= 6 | %ifndef __MEM16_INC__ 7 | %define __MEM16_INC__ 8 | 9 | [segment .text] 10 | ;;; _________________________________________________________________ 11 | init_heap: 12 | ;; 13 | ;; the heap begins behind the kernel end 14 | mov ax, kernel_end 15 | add ax, 0x0100 16 | shr ax, 4 17 | add ax, KERNEL_SEGM 18 | mov word [heap_seg], ax ; behind 19 | ;; set fs and gs to heap segment 20 | mov fs, ax 21 | mov gs, ax 22 | add ax, HEAP_SIZE 23 | mov word [cache_seg], ax 24 | add ax, CACHE_SIZE 25 | mov word [exe_seg], ax 26 | jnz .ok 27 | mov si, heap_error 28 | call display_string 29 | .hang: jmp .hang 30 | .ok: 31 | push es 32 | mov es, ax 33 | xor dx, dx 34 | mov word [es:0x0000], dx 35 | mov byte [es:0x0002], dl 36 | pop es 37 | 38 | mov si, heap_welcome 39 | call display_string 40 | mov dx, word[heap_seg] 41 | call dbg_print_word_dx 42 | mov si, endl 43 | call display_string 44 | 45 | retn 46 | heap_welcome db "Heap segment at ", 0 47 | heap_error db "ERROR initializing heap", 0 48 | 49 | ;; __________________________________________________________________ 50 | set_es_heap_seg: 51 | ;// es get_heap_segmnet(void) 52 | push word [heap_seg] 53 | pop es 54 | retf 55 | 56 | set_ds_heap_seg: 57 | ;// es get_heap_segmnet(void) 58 | push word [heap_seg] 59 | pop ds 60 | retf 61 | set_fs_heap_seg: 62 | push word [heap_seg] 63 | pop fs 64 | retf 65 | 66 | ;;; _________________________________________________________________ 67 | ;;; memcopy 68 | ;;; args: 69 | ;;; cx - count of bytes to copy 70 | ;;; ds:si - where from 71 | ;;; es:di - where to 72 | ;;; out: 73 | ;;; cf - if failed 74 | memcopy: 75 | rep movsb 76 | retf 77 | 78 | ;;; _________________________________________________________________ 79 | memalloc: 80 | ;// __far es:di memalloc(cx size) [ds!] 81 | ;;; args: 82 | ;;; cx - size of memory 83 | ;;; out: 84 | ;;; es:di - memory, NULL and CF if failed 85 | SIZEOF_HEADER equ 4 86 | push ds 87 | call KERNEL_SEGM : set_ds_heap_seg 88 | mov bx, SIZEOF_HEADER ; see from beginning 89 | .next_chunk: 90 | ; read header of chunk 91 | mov dx, word[bx - 4] ; dx - count of byte behind header 92 | mov al, byte[bx - 2] ; al - chunk info, 0 if free 93 | 94 | test dx, dx 95 | jz .heap_end ; if the end of heap 96 | ;; memory already had been allocated, but maybe free now 97 | test al, al 98 | jnz .goto_next ; occupied 99 | 100 | ;; is there enough space? 101 | mov ax, cx 102 | add ax, SIZEOF_HEADER 103 | sub ax, dx 104 | jge .goto_next 105 | ; - if equal, length of body will be 0, so jge. 106 | 107 | ;; allocate: 108 | ;; <-------- dx ---------> 109 | ;; <---- cx ---> 110 | ;; h1 new data h2 <-ax-> 111 | ;; |----|-----------|----|----| 112 | ;; bx-4 bx bx+cx bx+dx 113 | ;; <------ old chunk ---------> 114 | ; write h2 at [dx + cx + 4]: 115 | neg ax 116 | mov di, cx 117 | mov word [bx + di], ax 118 | mov byte [bx + di + 2], 0 ; free part 119 | 120 | ; write this chunk: 121 | mov word [bx - 4], cx 122 | mov byte [bx - 2], 0x01 ; occupied from now 123 | add cl, ch 124 | add cl, bl 125 | mov byte [bx - 1], cl ; control sum 126 | jmp .done 127 | 128 | .goto_next: ; occupied, go to next 129 | add bx, dx 130 | add bx, SIZEOF_HEADER 131 | jnc .next_chunk 132 | ;; no place 133 | xor bx, bx ; NULL 134 | jmp .done 135 | 136 | .heap_end: 137 | push dx 138 | mov dx, bx 139 | call dbg_print_word_dx 140 | pop dx 141 | ; allocate at the end 142 | mov word [bx - 4], cx 143 | mov byte [bx - 2], 0x01 144 | mov di, cx 145 | add cl, ch 146 | add cl, bl 147 | mov byte [bx - 1], cl ; check sum 148 | 149 | ;; dx == 0 150 | add di, bx 151 | mov word [di], dx 152 | mov word [di + 2], dx 153 | 154 | 155 | .done: ; result: 156 | ;lcall KERNEL_SEGM:set_es_heap_seg 157 | mov di, bx 158 | 159 | pop ds 160 | retf 161 | 162 | 163 | ;;; _________________________________________________________________ 164 | memfree: 165 | ;// __far cf memfree(ds:si pointer) 166 | ;;; args: 167 | ;;; si - where 168 | ;;; out: 169 | ;;; CF if failed 170 | push ds 171 | call KERNEL_SEGM:set_ds_heap_seg 172 | ;; check control sum, if addr is valid 173 | mov cx, si 174 | and cx, 0x00FF 175 | add cl, byte [si - 4] 176 | add cl, byte [si - 3] 177 | cmp cl, byte [si - 1] 178 | je .ok 179 | stc ; si is not a valid pointer 180 | jmp .done 181 | .ok: 182 | ;; clear 183 | xor ax, ax 184 | mov word[si - 2], ax ; clear state: now chunk is free 185 | mov bx, word [si - 4] ; look up next chunk 186 | ;; is the last? 187 | mov ax, word [si + bx] ; test if there is a next chunk 188 | test ax, ax 189 | jnz .done 190 | ;; no next chunk: 191 | mov word [si - 4], ax ; mark this as last 192 | .done: pop ds 193 | retf 194 | 195 | ;;; _________________________________________________________________ 196 | ;;; memset 197 | ;;; args: 198 | ;;; al - value 199 | ;;; cx - count 200 | ;;; es:di - where to 201 | 202 | ;;; _________________________________________________________________ 203 | ;;; memsetw 204 | ;;; -- "" -- 205 | ;;; ax - value 206 | 207 | [segment .data] 208 | 209 | heap_seg dw 0x0000 210 | cache_seg dw 0x0000 211 | exe_seg dw 0x0000 212 | 213 | %endif 214 | -------------------------------------------------------------------------------- /intrs.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Interrupts setter and handler for Dolphin OS kernel 3 | ; (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | 6 | %ifndef __INTR_INC 7 | %define __INTR_INC 8 | 9 | %macro SET_INT 1 10 | mov word [es : %1 * 4], int%1 11 | mov word [es : %1 * 4 + 2], KERNEL_SEGM 12 | %endmacro 13 | 14 | 15 | [segment .text] 16 | 17 | INTRTBL_SEGM equ 0x0000 18 | 19 | ; ___________________________________________________________________ 20 | ; intr_init 21 | ; initializes OS interrupts table 22 | 23 | intr_init: 24 | cli 25 | push es 26 | mov ax, INTRTBL_SEGM 27 | mov es, ax 28 | 29 | ;SET_INT 08h 30 | ;; for Ctrl-Break handling 31 | SET_INT 1Bh 32 | ;; exit from programs 33 | SET_INT 20h 34 | ;; every second alarm 35 | SET_INT 4Ah 36 | ;; seconds start 37 | int 4Ah 38 | 39 | pop es 40 | sti 41 | retn 42 | 43 | ; ___________________________________________________________________ 44 | ; int 1Bh 45 | ; handler of Ctrl-Break 46 | int1Bh: 47 | ;; clear stack 48 | popf 49 | pop ax 50 | pop ax 51 | ;; go to system loop 52 | push shell.system_loop 53 | retn 54 | 55 | ; ___________________________________________________________________ 56 | ; int 20h handler 57 | ; return to shell 58 | 59 | int20h: 60 | mov si, int20msg 61 | call display_string 62 | 63 | popf ; restore flags 64 | pop dx ; don't return to program 65 | pop bx 66 | 67 | call dbg_print_word_dx 68 | mov dx, bx 69 | call dbg_print_word_dx 70 | 71 | push shell.system_loop ; to system shell loop 72 | retn 73 | int20msg db "Int 20h executing...",13,10,0 74 | 75 | 76 | ; ___________________________________________________________________ 77 | ;; called every 1/55 sec 78 | int08h: 79 | pusha 80 | push es 81 | mov bx, KERNEL_SEGM 82 | mov es, bx 83 | mov ah, byte [es:show_clock] 84 | pop es 85 | test ah, ah 86 | jz .ret 87 | 88 | ;; clock 89 | call get_rtc_time 90 | ;; show time 91 | push cx 92 | push dx 93 | push es 94 | mov bx, TXTBUF_SEGM ;; video memory 95 | mov es, bx 96 | ;; tiny hack: cl needed for color, so cl will be out first 97 | ;; minutes 98 | mov dl, cl 99 | mov al, cl 100 | shr al, 4 101 | call hex_digit_to_ascii 102 | mov ah, 0x87 ;; TODO: neat clock colors :) 103 | mov bx, 0x004B ;; position 104 | call put_char 105 | mov al, dl 106 | and al, 0x0F 107 | call hex_digit_to_ascii 108 | inc bx 109 | call put_char 110 | ;; hours 111 | mov bx, 0x0048 112 | mov al, ch 113 | shr al, 4 114 | call hex_digit_to_ascii 115 | call put_char 116 | inc bx 117 | mov al, ch 118 | and al, 0x0F 119 | call hex_digit_to_ascii 120 | call put_char 121 | inc bx 122 | mov al, ':' 123 | call put_char 124 | add bx, 3 125 | call put_char 126 | ;; seconds 127 | inc bx 128 | mov al, dh 129 | shr al, 4 130 | call hex_digit_to_ascii 131 | call put_char 132 | inc bx 133 | mov al, dh 134 | and al, 0x0f 135 | call hex_digit_to_ascii 136 | call put_char 137 | 138 | pop es 139 | pop dx 140 | pop cx 141 | .ret: popa 142 | iret 143 | show_clock db 1 144 | 145 | ; ___________________________________________________________________ 146 | int4Ah: 147 | pusha 148 | ;; clock 149 | call get_rtc_time 150 | ;; check whether clock is running 151 | push es 152 | mov bx, KERNEL_SEGM 153 | mov es, bx 154 | mov ah, byte [es:show_clock] 155 | pop es 156 | test ah, ah 157 | jz .no_clock 158 | 159 | ;; show time 160 | push cx 161 | push dx 162 | push es 163 | mov bx, TXTBUF_SEGM ;; video memory 164 | mov es, bx 165 | ;; tiny hack: cl needed for color, so cl will be out first 166 | ;; minutes 167 | mov dl, cl 168 | mov al, cl 169 | shr al, 4 170 | call hex_digit_to_ascii 171 | mov ah, 0x0E ;; TODO: neat clock colors :) 172 | mov bx, 0x004B ;; position 173 | call put_char 174 | mov al, dl 175 | and al, 0x0F 176 | call hex_digit_to_ascii 177 | inc bx 178 | call put_char 179 | ;; hours 180 | mov bx, 0x0048 181 | mov al, ch 182 | shr al, 4 183 | call hex_digit_to_ascii 184 | call put_char 185 | inc bx 186 | mov al, ch 187 | and al, 0x0F 188 | call hex_digit_to_ascii 189 | call put_char 190 | inc bx 191 | mov al, ':' 192 | call put_char 193 | add bx, 3 194 | call put_char 195 | ;; seconds 196 | inc bx 197 | mov al, dh 198 | shr al, 4 199 | call hex_digit_to_ascii 200 | call put_char 201 | inc bx 202 | mov al, dh 203 | and al, 0x0f 204 | call hex_digit_to_ascii 205 | call put_char 206 | 207 | pop es 208 | pop dx 209 | pop cx 210 | 211 | ;; set next int4A for next second 212 | .no_clock: 213 | ;call next_second 214 | mov cx, 0xFFFF 215 | mov dh, 0xFF 216 | call set_alarm 217 | popa 218 | iret 219 | 220 | section .data 221 | 222 | %endif 223 | -------------------------------------------------------------------------------- /kernel.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This is a simplest kernel 3 | ; DolphinOS (c) Dmytro Sirenko, 2010 4 | ; ___________________________________________________________________ 5 | 6 | %include "sysdefs.inc" 7 | 8 | kernel_start: 9 | org KERNEL_OFFS 10 | [segment .text] 11 | cli 12 | ; prepare memory state 13 | mov ax, KERNEL_SEGM 14 | mov ds, ax ; use segment 0x0100 15 | mov es, ax ; 16 | 17 | mov ax, STACK_SEGM 18 | mov ss, ax ; 19 | mov sp, STACK_SIZE ; global stack size 0xFFFF 20 | sti 21 | 22 | ; initialize 23 | call intr_init 24 | call init_heap 25 | call fmount_fat12 26 | mov si, endl 27 | call display_string 28 | call press_any 29 | 30 | ; shell mode 31 | call shell 32 | 33 | ; ___________________________________________________________________ 34 | reboot: 35 | ; tries to reboot computer 36 | int 0x19 37 | 38 | ; ___________________________________________________________________ 39 | turnoff: 40 | ; turn off power for all bios-managed devices 41 | ; args: none 42 | mov ax, 5307h ; bios power management 43 | mov bx, 0001h ; all devices, where power managed by bios 44 | mov cx, 0003h ; state: off 45 | int 0x15 46 | ; ___________________________________________________________________ 47 | delay: 48 | ; void delay(ax ms) 49 | pusha 50 | mov cx, 1000 51 | mul cx 52 | jc .long 53 | xor cx, cx 54 | jmp .endif 55 | .long: mov cx, dx 56 | .endif: mov dx, ax 57 | mov ah, 86h 58 | int 15h 59 | popa 60 | retn 61 | 62 | ;; __________________________________________________________________ 63 | execute: 64 | ;// __far ax:status execute(ds:dx name) 65 | 66 | retf 67 | 68 | %include "heap.inc" 69 | %include "intrs.inc" 70 | %include "shell.inc" 71 | %include "time.inc" 72 | 73 | ;;; %include "fs.inc" we're not ready now to encapsulate 74 | %include "fat12.inc" ; \\\TODO: encapsulate it in fs.inc! 75 | 76 | 77 | [segment .data] 78 | build_date db __DATE__, 0 79 | build_time db __TIME__, 0 80 | 81 | ; the DATA segment! Otherwise kernel_end will be at the end of code, 82 | ; but before data and heap will overwrite kernel data 83 | kernel_end: 84 | -------------------------------------------------------------------------------- /pseudogr.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pseudographics routines 3 | ; DolphinOS (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | 6 | %ifndef __PSEUDOGRAPHICS_INC 7 | %define __PSEUDOGRAPHICS_INC 8 | 9 | section .data 10 | 11 | psgr: 12 | ;; corners 13 | .drt db 0xBB ;; double right-top 14 | .dlt db 0xC9 ;; left-top 15 | .drb db 0xBC ;; double right-bottom 16 | .dlb db 0xC8 ;; 17 | .srt db 0xBF 18 | .slt db 0xDA 19 | .srb db 0xD9 20 | .slb db 0xC0 21 | 22 | ;; lines 23 | .svl db 0xB3 ;; single vertical line 24 | .shl db 0xC4 ;; horisontal 25 | .dvl db 0xBA 26 | .dhl db 0xCD 27 | 28 | ;; bars 29 | .ff db 0xDB ;; fully filled rect 30 | .hdf db 0xDC ;; down-half filled rect 31 | .huf db 0xDF ;; up-half 32 | .hrf db 0xDE ;; right-half 33 | .hlf db 0xDD ;; left-half 34 | 35 | section .text 36 | 37 | ;; __________________________________________________________________ 38 | psgr_draw_dvl: 39 | ;; bh:bl - y:x, cx - length 40 | mov al, [psgr.dvl] 41 | 42 | call put_char 43 | retn 44 | 45 | ;; __________________________________________________________________ 46 | psgr_dframe: 47 | ;; draw double-lined frame 48 | retn 49 | 50 | %endif 51 | -------------------------------------------------------------------------------- /shell.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Simplest DolphinShell 3 | ; (c) Dmytro Sirenko, 2010 4 | ; ___________________________________________________________________ 5 | %ifndef __DSHELL_INC__ 6 | %define __DSHELL_INC__ 7 | 8 | %include "sysdefs.inc" 9 | 10 | ; ___________________________________________________________________ 11 | ; shell_main 12 | ; 13 | ; args, out: none 14 | shell: 15 | 16 | ; set video mode 17 | mov bx, 10bh 18 | call set_svga 19 | jne .svga_ok 20 | mov al, 03h ; set 80x25 16 colors mode 21 | call set_video_mode 22 | .svga_ok: 23 | 24 | mov al, 0x0B 25 | mov byte [text_attr], al 26 | mov dl, 20 ; cursor at the centre of screen 27 | mov dh, 10 28 | call set_cursor_pos 29 | mov si, welcome ; welcome message 30 | call display_string 31 | 32 | mov ax, 0x08 33 | mov byte [text_attr], al 34 | mov dl, 60 ; 35 | mov dh, 11 36 | call set_cursor_pos 37 | mov si, wlcm_help ; help message 38 | call display_string 39 | 40 | mov ax, 0x07 41 | mov byte [text_attr], al 42 | 43 | .system_loop: ; shell loop: prompt-command-run 44 | 45 | ; prompt 46 | mov si, msg_prompt 47 | call display_string 48 | 49 | ; read input 50 | call read_prompt 51 | ; is empty? 52 | mov al, byte [cmd_buf] 53 | test al, al 54 | jz .system_loop 55 | ; echo 56 | ;mov si, cmd_buf 57 | ;call display_string 58 | 59 | ; simplest actions 60 | mov si, .off 61 | call strcmpcmd 62 | je .turnoff 63 | cmp byte [cmd_buf], 'q' ; "q"uit 64 | jne .next0 65 | .turnoff: 66 | call turnoff 67 | mov si, .acpi_error 68 | jmp .system_loop 69 | .acpi_error db "Can`t shut down system: no valid ACPI", 13, 10, 0 70 | .off db "off", 0 71 | .next0: 72 | ;jmp .system_loop 73 | .next0a: 74 | mov si, .vga 75 | call strcmpcmd 76 | jne .next1 77 | call vga_trial 78 | jmp .system_loop 79 | .vga db "vga", 0 80 | .next1: 81 | mov si, .info ; "i"nfo ;;put ;;terrupts 82 | call strcmpcmd 83 | jne .next1a 84 | mov si, .lstr_heap_seg 85 | call display_string 86 | mov dx, [heap_seg] 87 | call dbg_print_word_dx 88 | mov si, .lstr_cache_seg 89 | call display_string 90 | mov dx, [cache_seg] 91 | call dbg_print_word_dx 92 | mov si, .lstr_cache_size 93 | call display_string 94 | mov dx, CACHE_SIZE 95 | call dbg_print_word_dx 96 | jmp .system_loop 97 | .info db "info", 0 98 | .lstr_heap_seg db "Heap segment at ", 0 99 | .lstr_cache_seg db 13, 10, "Cache segment at ", 0 100 | .lstr_cache_size db 13, 10, "Cache last byte: ", 0 101 | .next1a: 102 | mov si, .int 103 | call strcmpcmd 104 | jne .next2 105 | int 20h 106 | jmp .system_loop 107 | .int db "int", 0 108 | .next2: 109 | cmp byte [cmd_buf], 'b' ; "b"uild date/time 110 | jne .next2a 111 | mov si, endl 112 | call display_string 113 | mov si, build_date 114 | call display_string 115 | mov al, ' ' 116 | call out_char 117 | mov si, build_time 118 | call display_string 119 | jmp .system_loop 120 | .next2a: 121 | mov si, .help 122 | call strcmpcmd 123 | jne .next3 124 | mov si, .lstr_h 125 | call display_string 126 | 127 | jmp .system_loop 128 | .help db "help", 0 129 | .lstr_h db "Commands:", 13, 10, \ 130 | " q - turn off computer", 13, 10, \ 131 | " ascii - print ascii table", 13, 10, \ 132 | " keys - keys info, press q for exit", 13, 10, \ 133 | " dump - dump memory area, you`ll be prompted for params", 13, 10, \ 134 | " info - info about memory allocation", 13, 10, \ 135 | " cpu - cpu registers state", 13, 10, \ 136 | " cls/clear - clear screen", 13, 10, \ 137 | " delay - 5 second time delay", 13, 10, \ 138 | " vga - try some VGA graphics", 13, 10, \ 139 | " tetris - play tetris", 13, 10, \ 140 | " [ls - list of files in current directory]", 13, 10, \ 141 | 0 142 | .next3: 143 | cmp byte [cmd_buf], 'm' ; allocate "m"emory 144 | jne .next3a 145 | mov cx, 10 146 | push es 147 | call KERNEL_SEGM:memalloc 148 | mov [pointer], di 149 | mov dx, [heap_seg] 150 | call dbg_print_word_dx 151 | pop es 152 | jmp .system_loop 153 | .next3a: 154 | cmp byte [cmd_buf], 'r' ; "r"elease memory 155 | jne .next4 156 | mov si, [pointer] 157 | call KERNEL_SEGM:memfree 158 | jnc .system_loop 159 | mov si, .local_str01 160 | call display_string 161 | jmp .system_loop 162 | .local_str01 db "Memory release failed", 13, 10,0 163 | .next4: 164 | mov si, .dump 165 | call strcmpcmd 166 | jne .next5 167 | push es 168 | mov si, .lstr_memdump 169 | call display_string 170 | call dbg_hex_input_dx 171 | mov es, dx 172 | mov si, .lstr_dmoffs 173 | call display_string 174 | call dbg_hex_input_dx 175 | mov di, dx 176 | mov si, .lstr_dmcount 177 | call display_string 178 | call dbg_hex_input_dx 179 | mov cx, dx 180 | call dbg_dump_mem 181 | pop es 182 | jmp .system_loop 183 | .dump db "dump", 0 184 | .lstr_memdump db "Dump memory:", 13, 10, "segm: ", 0 185 | .lstr_dmoffs db "offs: ", 0 186 | .lstr_dmcount db "bytes: ", 0 187 | .next5: 188 | mov si, .delay 189 | call strcmpcmd 190 | jne .next6 191 | ;; delay 192 | mov si, .lstr_delay 193 | call display_string 194 | mov ax, 5000 195 | call delay 196 | ;; 197 | jmp .system_loop 198 | .delay db "delay", 0 199 | .lstr_delay db "There will be delay for 5 second...", 13, 10, 0 200 | .next6: 201 | mov si, .cls 202 | call strcmpcmd 203 | je .keya 204 | mov si, .clear 205 | call strcmpcmd 206 | jne .next7 207 | .keya: mov al, 03h ; set 80x25 16 colors mode 208 | call set_video_mode 209 | jmp .system_loop 210 | .cls db "cls", 0 211 | .clear db "clear", 0 212 | .next7: 213 | cmp byte [cmd_buf], 'l' ; "l"oad 214 | jne .next8 215 | mov dx, entry 216 | mov ax, 0 217 | call find_file_fat12 218 | mov bx, dx 219 | call print_fat_entry 220 | mov si, endl 221 | call display_string 222 | 223 | jmp .system_loop 224 | .next8: 225 | mov si, .tetris 226 | call strcmpcmd 227 | jne .next9 228 | ;call KERNEL_SEGM:PlayTetris 229 | jmp .system_loop 230 | .tetris db "tetris", 0 231 | .next9: 232 | mov si, .ascii 233 | call strcmpcmd 234 | jne .nextA 235 | call show_ascii_table 236 | jmp .system_loop 237 | .ascii db "ascii", 0 238 | .nextA: 239 | mov si, .cpu_state 240 | call strcmpcmd 241 | jne .nextB 242 | call dbg_window_cpu 243 | jmp .system_loop 244 | .cpu_state db "cpu", 0 245 | .nextB: 246 | mov si, .keys 247 | call strcmpcmd 248 | jne .nextC 249 | .next_key: 250 | call show_key_info 251 | cmp al, 'q' 252 | jne .next_key 253 | jmp .system_loop 254 | .keys db "keys", 0 255 | .nextC: 256 | mov si, .color 257 | call strcmpcmd 258 | mov byte [text_attr], 0x70 259 | jne .nextD 260 | .color db "white", 0 261 | .nextD: 262 | jmp .not_found 263 | ;; here should be parameters parsing 264 | 265 | ;; try to find executable 266 | push es 267 | mov es, word [exe_seg] 268 | mov di, COM_OFFSET 269 | mov si, cmd_buf 270 | call upload_file 271 | ;; if all ok, jump to file 272 | jc .not_found 273 | push es 274 | push di 275 | retf 276 | ;; return with int 20h 277 | .not_found: 278 | pop es 279 | 280 | ;; not found 281 | mov si, unknown_cmd 282 | call display_string 283 | jmp .system_loop 284 | ; end of system body 285 | 286 | 287 | ; ___________________________________________________________________ 288 | set_svga: 289 | ; tries to set svga video mode 290 | ; args: bx - number of svga mode, 108h for 80x60, 10Bh for 132x50 291 | mov al, 02 292 | mov ah, 4Fh 293 | int 10h 294 | cmp al, 4Fh 295 | je svga_ret 296 | mov si, svga_err 297 | call display_string 298 | svga_ret: 299 | retn 300 | 301 | ; ___________________________________________________________________ 302 | strcmpcmd: 303 | pusha 304 | mov di, cmd_buf 305 | .next: cmpsb 306 | jne .ret 307 | mov ah, byte [si] 308 | test ah, ah 309 | jnz .next 310 | .ret: popa 311 | retn 312 | 313 | %include "vga.inc" 314 | %include "stdio.inc" 315 | ;%include "tetris.inc" 316 | 317 | [segment .data] 318 | ; ___________________________________________________________________ 319 | ; _________________ DATA ____________________________________________ 320 | ; ___________________________________________________________________ 321 | 322 | ; ___________________________________________________________________ 323 | ; standard messages 324 | welcome db "Welcome to DolphinOS", 13, 10, 0 325 | wlcm_help db "type help for help", 13, 10, 0 326 | svga_err db 'SVGA not supported', 10, 0 327 | unknown_cmd db "Unknown command or file not found", 13, 10, \ 328 | "Type help for command list", 13, 10, 0 329 | msg_prompt db 13, 10, '>> ', 0 330 | 331 | ; buffers 332 | cmd_buf times MAX_CMDLINE_LENGTH db 0 333 | dir_path times MAX_PATH_LENGTH db 0 334 | path db ".;/bin;" 335 | times PATH_VAR_LENGTH-($-path) db 0 336 | 337 | ;;;; TEMP 338 | pointer dw 0x0000 339 | entry times 20 db 0 340 | 341 | %endif 342 | -------------------------------------------------------------------------------- /stdio.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains routins for text i/o 3 | ; (c) Dmytro Sirenko, 2010 4 | ; ____________________________________________________________________ 5 | 6 | %ifndef __TEXTMODE_INC 7 | %define __TEXTMODE_INC 8 | 9 | %include "sysdefs.inc" 10 | %include "string.inc" 11 | 12 | [segment .text] 13 | 14 | ; ___________________________________________________________________ 15 | hex_to_ascii: 16 | cmp al, 10 17 | sbb al, 96h 18 | das 19 | ret 20 | 21 | ; ___________________________________________________________________ 22 | display_string: 23 | ; displays string in ds:si 24 | ; args: si - offset of a string to display 25 | pusha 26 | mov ah, 0x0E 27 | movzx bx, byte [text_attr] 28 | .iter: 29 | mov al, [si] 30 | and al, al 31 | jz .done 32 | int 0x10 33 | lodsb 34 | jmp .iter 35 | .done: popa 36 | retn 37 | 38 | ; ___________________________________________________________________ 39 | set_cursor_pos: 40 | ; args: dh - line, dl - column 41 | xor bx, bx 42 | mov ah, 02h ; bios func num 43 | int 10h 44 | retn 45 | 46 | ; ___________________________________________________________________ 47 | get_cursor_pos: 48 | ; args: none 49 | ; out: dh - line, dl - column 50 | xor bx, bx 51 | mov ah, 03h 52 | int 10h 53 | retn 54 | 55 | 56 | ; ___________________________________________________________________ 57 | wait_key: 58 | get_char: 59 | ; waits for a key press, returns it 60 | ; args: none 61 | ; out: al - ASCII-code, 0, or scan-code prefix 62 | ;;; mov ah, 10h ; 101/102 keys 63 | ;;; int 16h ; - this stinking interrupt loads 95% CPU! 64 | ;int 0x4A 65 | .loop: 66 | mov ax, 20 67 | call delay 68 | mov ah, 11h 69 | int 16h 70 | jz .loop 71 | push ds 72 | push 0 73 | pop ds 74 | mov dx, word [041Ah] 75 | mov word [041Ch], dx ; clear buffer 76 | cmp al, 03 ; Ctrl-C handler 77 | jne .next0 78 | pop ds 79 | push shell.system_loop 80 | jmp .ret 81 | .next0: 82 | cmp al, 0x0C 83 | jne .ret 84 | ;; it should be an interrupt 85 | ; jmp .ret 86 | .ret: 87 | pop ds 88 | retn 89 | 90 | out_char: 91 | ; echo a character in al 92 | pusha 93 | mov ah, 0x0E 94 | movzx bx, byte [text_attr] 95 | int 0x10 96 | popa 97 | retn 98 | 99 | out_color_char: 100 | ; args: al - ascii, bl - color attrs 101 | pusha 102 | mov ah, 0x0E 103 | mov bh, 0x00 104 | int 10h 105 | popa 106 | retn 107 | 108 | put_char: 109 | ;; args: 110 | ;; ah - color attr, al - ascii, bh:bl - y:x 111 | pusha 112 | mov cx, ax 113 | movzx ax, bh 114 | movzx dx, byte [screen_width] 115 | mul dl 116 | movzx dx, bl 117 | add ax, dx 118 | shl ax, 1 119 | push es 120 | mov bx, TXTBUF_SEGM 121 | mov es, bx 122 | mov bx, ax 123 | mov word [es:bx], cx 124 | pop es 125 | popa 126 | retn 127 | 128 | ; ___________________________________________________________________ 129 | press_any: 130 | ; show "Press any key" message and waits for it 131 | mov si, pakmsg 132 | call display_string 133 | call wait_key 134 | ret 135 | pakmsg db 13, 10, "Press any key to continue...", 13, 10, 0 136 | 137 | ; ___________________________________________________________________ 138 | read_prompt: 139 | ; loop until enter is pressed, fills cmd_buf. 140 | ; args, outs: none 141 | mov cx, 0 ; counter 142 | mov di, cmd_buf 143 | 144 | .type_loop: ; while enter will be pressed 145 | call get_char 146 | ; check whether a char is ascii 147 | cmp al, 20h ; gap ascii code 148 | jl .char_skipped 149 | test al, 80h 150 | jnz .char_skipped 151 | ; all is right 152 | stosb ; add to cmd_buf 153 | call out_char ; echo 154 | .char_skipped: 155 | .bksp: cmp al, 0x08 156 | jne .enter 157 | ; remove last character 158 | mov word [di], 0 159 | ; is the first? 160 | cmp di, cmd_buf 161 | jle .type_loop 162 | dec di 163 | ; don't leave tracks 164 | mov al, 0x08 165 | call out_char 166 | mov al, ' ' 167 | call out_char 168 | mov al, 0x08 169 | call out_char 170 | jmp .type_loop 171 | .enter: 172 | cmp al, 0x0D ; enter ? 173 | jne .type_loop 174 | 175 | ; push the end of line into cmd_buf 176 | mov al, 0 177 | stosb 178 | 179 | ; print end of line 180 | mov al, 13 181 | call out_char 182 | mov al, 10 183 | call out_char 184 | retn 185 | 186 | ; ___________________________________________________________________ 187 | set_video_mode: 188 | ; sets video mode for text 189 | ; arguments: video mode in al (03h by default) 190 | test al, al 191 | jnz vm_ok 192 | mov al, 03h 193 | vm_ok: 194 | mov ah, 00h 195 | int 10h 196 | retn 197 | 198 | ;; __________________________________________________________________ 199 | show_ascii_table: 200 | mov si, .asciimsg 201 | call display_string 202 | xor cx, cx 203 | .asc_l: 204 | mov si, endl 205 | call display_string 206 | xor di, di 207 | .asc_l1: 208 | mov al, cl 209 | shl al, 4 210 | add ax, di 211 | call out_char 212 | mov al, ' ' 213 | call out_char 214 | inc di 215 | cmp di, 0x10 216 | jl .asc_l1 217 | inc cx 218 | cmp cx, 0x10 219 | jl .asc_l 220 | 221 | retn 222 | .asciimsg db "Ascii table:", 13, 10, 0 223 | 224 | ;; __________________________________________________________________ 225 | show_key_info: 226 | ;; 227 | call get_char 228 | 229 | mov si, .str_symb 230 | call display_string 231 | mov dl, al 232 | call dbg_print_char_dl 233 | 234 | mov si, .str_ascii 235 | call display_string 236 | call dbg_print_hex_dl 237 | 238 | test dl, dl 239 | jz .ext 240 | mov si, .str_scan 241 | jmp .end 242 | .ext: mov si, .str_ext 243 | .end: call display_string 244 | mov dl, ah 245 | call dbg_print_hex_dl 246 | 247 | mov si, endl 248 | call display_string 249 | retn 250 | .str_symb db 13, 10, "Symbol: ", 0 251 | .str_ascii db 13, 10, "Ascii : ", 0 252 | .str_ext db 13, 10, "ExtAsc: ", 0 253 | .str_scan db 13, 10, "Scan : ", 0 254 | 255 | ;; __________________________________________________________________ 256 | ;; _________________ DATA and defines _____________________________ 257 | ;; __________________________________________________________________ 258 | [segment .data] 259 | 260 | endl db 13, 10, 0 261 | clsymb db 8, ' ', 8, 0 262 | 263 | text_attr db 0x07 264 | screen_width db 80 265 | screen_height db 25 266 | 267 | %endif 268 | -------------------------------------------------------------------------------- /string.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; string routines 3 | ; DolphinOS (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | 6 | %ifndef __STRING_INC 7 | %define __STRING_INC 8 | 9 | DEF_DELIMITER equ ' ' 10 | 11 | section .text 12 | 13 | ; ___________________________________________________________________ 14 | si_to_hex_dx: 15 | ;; reads stream at [si] until hex word will be read 16 | ;; default delimiter is ' ' 17 | ;; args: si - stream beginning 18 | ;; outs: dx - read word 19 | ;; notes: HHHH, HHH, HH, HHHHh options are acceptable 20 | ;; does not preserve registers! si is moved to last read position. 21 | ;; read delimiters before 22 | mov al, DEF_DELIMITER 23 | .next_delim: 24 | cmp al, byte [si] ;; scasb moves automatically, don't use it 25 | jne .end_delim 26 | inc si 27 | jmp .next_delim 28 | .end_delim: 29 | ;; leading zeroes 30 | mov al, '0' 31 | .next_zero: 32 | cmp al, byte [si] 33 | jne .end_zero 34 | inc si 35 | jmp .next_zero 36 | .end_zero: 37 | ;; number must be here 38 | mov cx, 4 39 | .next_digit: 40 | 41 | loop .next_digit 42 | .error: 43 | .end_number: 44 | retn 45 | 46 | 47 | 48 | ; ___________________________________________________________________ 49 | hex_digit_to_ascii: 50 | ;; args: al - byte 0..F 51 | ;; outs: al - '0'..'9', 'A'..'F' 52 | push bx 53 | mov bl, al 54 | sub al, 10 55 | jl .dec 56 | .hex: add al, 'A' 57 | jmp .ret 58 | .dec: add bl, '0' 59 | mov al, bl 60 | .ret: pop bx 61 | retn 62 | 63 | 64 | %endif 65 | -------------------------------------------------------------------------------- /sysdefs.inc: -------------------------------------------------------------------------------- 1 | %ifndef __SYS_DEFS_INC 2 | %define __SYS_DEFS_INC 3 | 4 | MAX_CMDLINE_LENGTH equ 256 5 | MAX_PATH_LENGTH equ 256 6 | PATH_VAR_LENGTH equ 256 7 | 8 | VGAMEM_SEGM equ 0xA000 9 | TXTBUF_SEGM equ 0xB800 10 | VGA13h_MAX_X equ 320 11 | VGA13h_MAX_Y equ 200 12 | 13 | KERNEL_SEGM equ 0x0100 14 | KERNEL_OFFS equ 0x0000 15 | 16 | STACK_SEGM equ 0x9000 17 | 18 | BOOT_SEG equ 0x07c0 19 | BOOT_MEM equ 0x0000 20 | 21 | HEAP_SIZE equ 0x1000 ;; 22 | CACHE_SIZE equ 0x0800 ;; 23 | STACK_SIZE equ 0x1000 ;; 24 | 25 | COM_OFFSET equ 0x0100 26 | 27 | ;SCREEN_WIDTH equ 80 28 | ;SCREEN_HEIGHT equ 25 29 | 30 | ;; __________ KEYBOARD __________________________________________ 31 | ;; state at 0x00417 32 | KB1_RIGHT_SHIFT equ 0x01 33 | KB1_LEFT_SHIFT equ 0x02 34 | KB1_ANY_CTRL equ 0x04 35 | KB1_ANY_ALT equ 0x08 36 | KB1_SCRLK_ON equ 0x10 37 | KB1_NUMLK_ON equ 0x20 38 | KB1_CPSLK_ON equ 0x40 39 | KB1_INSERT_ON equ 0x80 40 | 41 | ;; state at 0x00418 42 | KB2_LEFT_CTRL_PRESSED equ 0x01 43 | KB2_LEFT_ALT_PRESSED equ 0x02 44 | KB2_RIGHT_CTRL_PRESSED equ 0x04 45 | KB2_RIGHT_ALT_PRESSED equ 0x08 46 | KB2_SCRLK_PRESSED equ 0x10 47 | KB2_NUMLK_PRESSED equ 0x20 48 | KB2_CPSLK_PRESSED equ 0x40 49 | KB2_SYSRQ_PRESSED equ 0x80 50 | 51 | 52 | 53 | ; _________ fopen function params _________________________________ 54 | F_READ equ 0x01 55 | F_WRITE equ 0x02 56 | F_APPEND equ 0x03 57 | 58 | ; _________ fopen error codes _____________________________________ 59 | E_NOT_FOUND equ 0xFF 60 | E_READONLY equ 0xFE 61 | 62 | E_INVALID_FILE_NAME equ 0xF0 63 | 64 | NO_ERROR equ 0 65 | 66 | %endif 67 | -------------------------------------------------------------------------------- /tetris.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; Tetris for DolphinOS 3 | ; (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | %ifndef __TETRIS_INC 6 | %define __TETRIS_INC 7 | 8 | %include "stdio.inc" 9 | 10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 11 | segment .text 12 | 13 | %macro BEGIN_TXT_DRAW 0 14 | push es 15 | mov dx, TXTBUF_SEGM 16 | mov es, dx 17 | %endmacro 18 | 19 | %macro END_TXTDRAW 0 20 | pop es 21 | %endmacro 22 | 23 | ;; __________________________________________________________________ 24 | PlayTetris: 25 | xor ax, ax 26 | call set_video_mode 27 | mov si, tetris.welcome 28 | call display_string 29 | 30 | BEGIN_TXT_DRAW 31 | call tetris_start 32 | 33 | call tetris_main 34 | END_TXTDRAW 35 | 36 | movzx dx, [tetris.x0] 37 | call dbg_print_word_dx 38 | movzx dx, [tetris.y0] 39 | call dbg_print_word_dx 40 | 41 | retf 42 | 43 | ;; __________________________________________________________________ 44 | tetris_start: 45 | ;; x0-y0: 46 | movzx ax, byte [ds : tetris.width] 47 | movzx bx, byte [ds : screen_width] 48 | sub bx, ax 49 | shr bx, 1 50 | mov byte [ds : tetris.x0], bl 51 | ; 52 | movzx ax, byte [ds : tetris.height] 53 | movzx bx, byte [ds : screen_height] 54 | sub bx, ax 55 | shr bx, 1 56 | mov byte [ds : tetris.y0], bl 57 | 58 | ;; clear tetris fields 59 | 60 | movzx ax, byte [ds : tetris.y0] 61 | mul byte [screen_width] 62 | movzx dx, byte [ds : tetris.x0] 63 | add ax, dx 64 | shl ax, 1 65 | 66 | movzx dx, byte [ds : tetris.height] 67 | 68 | mov bh, TTRS_FREE_CELL ;; free cell color 69 | mov bl, ' ' ;; fill cell 70 | 71 | .next_line: 72 | mov di, ax 73 | push ax 74 | mov ax, bx 75 | movzx cx, byte [ds : tetris.width] 76 | rep stosw 77 | pop ax 78 | movzx cx, byte [ds : screen_width] 79 | shl cx, 1 80 | add ax, cx 81 | dec dx 82 | jnz .next_line 83 | ; 84 | 85 | retn 86 | 87 | ;; __________________________________________________________________ 88 | tetris_main: 89 | ;; check state and move tetris down if possible 90 | call ttrs_new_shape 91 | 92 | .main_loop: 93 | ;; delay 94 | mov ax, 80 ;; ms 95 | call delay 96 | 97 | ;; check keyboard 98 | mov ah, 0x11 99 | int 0x16 100 | jz .fall_further 101 | ;; key is pressed 102 | ; clear keyboard buffer 103 | mov ah, 0x10 104 | int 0x16 105 | ; handle 106 | cmp al, 'q' 107 | je .end 108 | .fall_further: 109 | ;; layout checkout 110 | call tetris_checkout 111 | jnc .main_loop 112 | ;; run new shape 113 | call ttrs_new_shape 114 | jnc .main_loop 115 | .end: 116 | retn 117 | 118 | ;; __________________________________________________________________ 119 | ttrs_new_shape: 120 | ;; puts random shape at top of the screen 121 | ;; rets: 122 | ;; cf=1 if there's no place 123 | ;; convert all existing falling cells to mass 124 | mov bh, byte [tetris.height] 125 | .cnext_line: 126 | dec bh 127 | jl .cend 128 | xor bl, bl 129 | .cnext_cell: 130 | call ttrs_get_cell 131 | cmp ah, TTRS_FALL_CELL 132 | jne .cnext 133 | mov al, 0x9F 134 | call ttrs_set_cell 135 | .cnext: inc bl 136 | cmp bl, byte [tetris.width] 137 | jl .cnext_cell 138 | jmp .cnext_line 139 | .cend: 140 | 141 | ;; put new figure 142 | mov bh, 0x00 143 | mov bl, byte [ds : tetris.width] 144 | shr bl, 1 145 | sub bl, 2 146 | call ttrs_video_addr 147 | mov di, ax ;; DI will be holder for videomem addr 148 | ; choose shape 149 | call ttrs_random 150 | shl ax, 3 ;; mul by 8, size of shape images 151 | add ax, tetr_primitives 152 | mov si, ax ; now si contains mask 153 | ; read mask: 154 | mov cx, 0x000F ;; bit counter 155 | .next_mask_symb: 156 | bt word [ds : si], cx ;; copy CXth bit from [SI] to CF 157 | jnc .next ;; if zero, we don't need put smth here 158 | ; check whether is possible to put cell 159 | mov ax, word [es : di] 160 | cmp ah, TTRS_FREE_CELL 161 | je .cell_ok 162 | ;;;;;; end of game, there's no place for new figure 163 | stc 164 | retn 165 | .cell_ok: 166 | mov dh, TTRS_FALL_CELL 167 | mov dl, TTRS_BLOCK_ASCII 168 | mov word [es : di], dx 169 | .next: 170 | test cl, 0x03 ;; divisible by 4? 171 | jnz .mask_next 172 | ;; we need to go to next line 173 | sub di, 8 ;; LF :) 174 | mov ax, di 175 | call ttrs_down_cell ;; CR :) 176 | mov di, ax 177 | .mask_next: 178 | add di, 2 179 | dec cx 180 | jge .next_mask_symb 181 | .ret: clc ;; all is ok 182 | retn 183 | 184 | ;; __________________________________________________________________ 185 | ttrs_fall_aside: 186 | ;; move falling figure by one cell aleft or aright if possible 187 | ;; args: 188 | ;; di=0 - left, di=1 - right 189 | 190 | ;; find quad that contains falling figure 191 | ;; and check whether all cells can be moved 192 | mov bh, byte [tetris.height] 193 | ; cx will be (x1, y1), dx (x2, y2) 194 | mov cx, word [tetris.width] ;; .height is just after .width 195 | xor dx, dx 196 | xor si, si ;; si=0 - move is possible 197 | .cnext_line: 198 | dec bh 199 | jl .cend 200 | xor bl, bl 201 | .cnext_cell: 202 | call ttrs_get_cell 203 | cmp ah, TTRS_FALL_CELL 204 | jne .cnext 205 | ;; 206 | ; check whether move is possible 207 | test di, di 208 | jz .left 209 | inc bl 210 | cmp bl, byte [tetris.width] 211 | jge .ret 212 | call ttrs_get_cell 213 | cmp ah, TTRS_FALL_CELL 214 | je .fall_ok 215 | cmp ah, TTRS_FREE_CELL 216 | jne .ret 217 | .fall_ok: 218 | dec bl 219 | jmp .eif 220 | .left: dec bl 221 | cmp bl, 0 222 | jle .ret 223 | call ttrs_get_cell 224 | cmp ah, TTRS_FALL_CELL 225 | je .fa_ok 226 | cmp ah, TTRS_FREE_CELL 227 | jne .ret 228 | .fa_ok: inc bl 229 | .eif: 230 | ; check bounds 231 | cmp ch, bh 232 | cmovg ch, bh 233 | cmp dh, bh 234 | cmovl dh, bh 235 | 236 | cmp cl, bl 237 | cmovg cl, bl 238 | cmp dl, bl 239 | cmovl dl, bl 240 | ;; 241 | .cnext: inc bl 242 | cmp bl, byte [tetris.width] 243 | jl .cnext_cell 244 | jmp .cnext_line 245 | .cend: 246 | mov bx, cx 247 | 248 | 249 | .next: 250 | ;; Move this cell 251 | call ttrs_get_cell 252 | test di, di 253 | jz .move_left 254 | dec bl 255 | 256 | inc bl 257 | .move_left: 258 | 259 | .endif: 260 | ;; 261 | inc bl 262 | cmp bl, dl 263 | jl .next 264 | mov bl, cl 265 | inc bh 266 | cmp bh, dh 267 | jl .next 268 | .ret: 269 | retn 270 | 271 | ;; __________________________________________________________________ 272 | ttrs_down_cell: 273 | ; args: ax - addr of cell 274 | ; rets: ax - addr down by one cell 275 | movzx dx, byte [screen_width] 276 | shl dx, 1 277 | add ax, dx 278 | retn 279 | 280 | ttrs_up_cell: 281 | ; see above, just up 282 | movzx dx, byte [screen_width] 283 | shl dx, 1 284 | sub ax, dx 285 | retn 286 | 287 | ;; __________________________________________________________________ 288 | tetris_checkout: 289 | ;; check fields from bottom to top 290 | ;; if there's a filled line, remove it 291 | ;; if there's a falling shape, move it down if possible, 292 | ;; else return cf=1 293 | ;; calculate last cell addr in videomem 294 | mov bh, byte [tetris.height] 295 | 296 | .next_line: 297 | dec bh 298 | jl .ret 299 | xor bl, bl 300 | ;; cycle init: 301 | stc ;; flag of full line 302 | .next_block: 303 | push bx 304 | call ttrs_video_addr 305 | mov di, ax 306 | mov ax, word [es:di] 307 | cmp ah, TTRS_FREE_CELL 308 | jne .else 309 | clc 310 | jmp .endif 311 | .else: cmp ah, TTRS_FALL_CELL 312 | jne .endif 313 | clc 314 | ;; move this cell by one cell down 315 | inc bh ;; check cell below 316 | cmp bh, byte [tetris.height] 317 | jl .bottom_ok 318 | .landing: 319 | pop bx 320 | stc 321 | retn 322 | .bottom_ok: 323 | ;; check whether cell below is occupied 324 | ;push bx ;; internal push bx 325 | call ttrs_get_cell 326 | cmp ah, TTRS_FREE_CELL 327 | je .occupied_ok 328 | cmp ah, TTRS_FALL_CELL 329 | jne .landing 330 | .occupied_ok: 331 | ; set cell below as this 332 | mov al, TTRS_FALL_CELL 333 | call ttrs_set_cell 334 | dec bh 335 | ; clear trace) 336 | mov al, TTRS_FREE_CELL 337 | call ttrs_set_cell 338 | .endif: 339 | pop bx 340 | inc bl 341 | cmp bl, byte [tetris.width] 342 | jl .next_block 343 | 344 | ;; if full, delete, sheer and go to next line 345 | jnc .not_full 346 | clc 347 | ;;; sheer all 348 | .not_full: 349 | jmp .next_line 350 | .ret: clc 351 | retn 352 | 353 | ;; __________________________________________________________________ 354 | ttrs_video_addr: 355 | ;; args: 356 | ;; bh - y, 357 | ;; bl - x (for tetris) 358 | ;; rets: 359 | ;; ax - addr of field in videomem 360 | ;; notes: 361 | ;; warning: corrupts GS value! 362 | pusha 363 | movzx ax, bh 364 | add al, byte [tetris.y0] 365 | mul byte [screen_width] 366 | movzx dx, byte [tetris.x0] 367 | add ax, dx 368 | movzx dx, bl 369 | add ax, dx 370 | shl ax, 1 371 | mov word[.res], ax 372 | popa 373 | mov ax, word[.res] 374 | retn 375 | .res dw 0x0000 376 | 377 | ;; __________________________________________________________________ 378 | ttrs_get_cell: 379 | ;; args: 380 | ;; bh - y rel. to x0-y0 381 | ;; bl - x rel. to x0-y0 382 | ;; outs: 383 | ;; al - text_attr for this cell 384 | ;; ah - ascii there 385 | push bx 386 | call ttrs_video_addr 387 | mov bx, ax 388 | mov ax, word [es : bx] 389 | pop bx 390 | retn 391 | 392 | ;; __________________________________________________________________ 393 | ttrs_set_cell: 394 | ;; args: 395 | ;; bh - y 396 | ;; bl - x 397 | ;; al - attr 398 | pusha 399 | mov dh, al 400 | call ttrs_video_addr 401 | mov bx, ax 402 | mov dl, TTRS_BLOCK_ASCII 403 | mov word [es:bx], dx 404 | popa 405 | retn 406 | 407 | ;; __________________________________________________________________ 408 | ttrs_random: 409 | ;; gets number from 0 to 6 in ax 410 | ;;;;; just a STUB! 411 | mov ax, 4 412 | ;; call get_rtc_time 413 | retn 414 | 415 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 416 | section .data 417 | 418 | TTRS_FREE_CELL equ 0x8F 419 | TTRS_FALL_CELL equ 0x0C 420 | TTRS_MASS_MASK equ 0x77 421 | 422 | tetris: 423 | .welcome db "Tetris for DolphinOS", 13, 10, \ 424 | "[under development]", 13, 10, \ 425 | "(c) Dmytro Sirenko, 2010", 13, 10, 0 426 | .width db 26 427 | .height db 20 428 | 429 | .x0 db 00 430 | .y0 db 00 431 | 432 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 433 | tetr_primitives: 434 | ;; this records contains mask 4x4 bit for shapes: 435 | ;; 4x4 (2 byte) mask for shape: 4 times for 4 turns 436 | ;; 437 | .line dw 0x4444, 0x0F00, 0x4444, 0x0F00 438 | .block dw 0xCC00, 0xCC00, 0xCC00, 0xCC00 439 | .rbreak dw 0x4620, 0x6C00, 0x4620, 0x6c00 440 | .lbreak dw 0x4c80, 0xC600, 0x4C80, 0xc600 441 | .rangle dw 0x6440, 0x0E20, 0x44C0, 0x8E00 442 | .langle dw 0xC440, 0x2E00, 0x4460, 0x0E80 443 | .trngl dw 0x4E00, 0x4640, 0x0E40, 0x4C40 444 | 445 | .debug dw 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF 446 | 447 | TTRS_PRIM_COUNT equ 8 448 | TTRS_BLOCK_ASCII equ ' ' 449 | 450 | %endif 451 | -------------------------------------------------------------------------------- /time.inc: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; 3 | ;; 4 | ;; __________________________________________________________________ 5 | %ifndef __TIME_INC 6 | %define __TIME_INC 7 | 8 | section .text 9 | 10 | get_rtc_date: 11 | ;; success: cf=0 12 | ;; args: none 13 | ;; outs: 14 | ;; cx - bcd year (1998h for 1998) 15 | ;; dh - bcd month 16 | ;; dl - bcd day 17 | mov ah, 0x04 18 | int 0x1A 19 | retn 20 | 21 | get_rtc_time: 22 | ;; cf = 0 success 23 | ;; args: none 24 | ;; outs: 25 | ;;  ch:dl:dh - (bcd) hh:mm:ss 26 | mov ah, 0x02 27 | int 0x1A 28 | retn 29 | 30 | set_rtc_date: 31 | ;; args: 32 | ;; cx:dh:dl - (BCD) yyyy:mm:dd 33 | mov ah, 0x05 34 | int 0x1A 35 | retn 36 | 37 | set_rtc_time: 38 | ;; args: 39 | ;; ch:cl:dh - (bcd) hh:mm:ss 40 | ;; dl - 01 for summer time, 0 otherwise 41 | mov ah, 0x03 42 | int 0x1A 43 | retn 44 | 45 | get_sys_time: 46 | ;; args: none 47 | ;; outs: 48 | ;; cx:dx - counter 49 | ;; al - counter overflow byte 50 | xor ah, ah 51 | int 0x1A 52 | retn 53 | 54 | set_alarm: 55 | ;; args: 56 | ;; ch:cl:dh - (bcd) hh:mm:ss for irq8 (int 0x4A) 57 | mov ah, 0x06 58 | int 0x1a 59 | retn 60 | 61 | next_second: 62 | ;; args: ch:cl:dh - hh:mm:ss (bcd) 63 | ;; out: ch:cl:dh - hh:mm:ss+1 (bcd) 64 | push ax 65 | movzx ax, dh 66 | inc al 67 | daa 68 | mov dh, al 69 | cmp dh, 0x60 70 | jl .ok 71 | xor dh, dh 72 | mov al, cl 73 | inc al 74 | daa 75 | mov cl, al 76 | cmp cl, 0x60 77 | jl .ok 78 | xor cl, cl 79 | mov al, ch 80 | inc al 81 | daa 82 | mov ch, al 83 | cmp ch, 0x24 84 | jl .ok 85 | xor ch, ch 86 | .ok: pop ax 87 | retn 88 | 89 | %endif 90 | -------------------------------------------------------------------------------- /tmp.inc: -------------------------------------------------------------------------------- 1 | ;;; _________________________________________________________________f 2 | find_first_fat12: 3 | ;// zf find_first(ax dir_cluster, dx *entry) 4 | pusha 5 | push es 6 | push ds 7 | test ax, ax ; 0 - root sector 8 | jz .root 9 | call _cluster_to_sector 10 | jmp .endif 11 | .root: mov ax, word [rootSector] 12 | .endif: xor bx, bx 13 | mov cx, word [cache_seg] 14 | mov es, cx 15 | call _read_sector ; read in es:bx 16 | 17 | push ds 18 | push es 19 | pop ds 20 | pop es 21 | 22 | mov si, bx 23 | mov di, dx 24 | mov cx, SIZEOF_FAT_ENTRY 25 | rep movsb 26 | 27 | pop ds 28 | pop es 29 | popa 30 | retn 31 | 32 | ;;; _________________________________________________________________ 33 | find_next_fat12: 34 | ;// zf find_next(ax dir_cluster, dx *entry) 35 | test ax, ax 36 | jz .root 37 | 38 | .root: 39 | mov 40 | 41 | retn 42 | 43 | ;;; _________________________________________________________________ 44 | 45 | 46 | lookup_cluster_value: 47 | ;;// ax get_next_cluster(ax cluster) 48 | ;;; 0 if the end of file 49 | ;; find number of FAT sector which contains given cluster 50 | ;; sector_for_clustval = bpb.reserved + 51 | ;; (clust_num * 3 / 2) / bpb.BpS 52 | push ax ;; save cluster num 53 | ; mul by 3 54 | mov dx, ax 55 | shl dx, 1 56 | add ax, dx 57 | ; 58 | shr ax, 1 59 | div word [bpb.BpS] 60 | mov di, dx ;; store remainder 61 | add word [bpb.reserved] 62 | ;; load it into CACHE_SEG:0000 63 | push es 64 | mov bx, word [cache_seg] 65 | mov es, bx 66 | xor bx, bx 67 | call _read_sector 68 | ;jnc .ok 69 | mov dx, word [es:di] 70 | pop es 71 | pop ax ;; restore cluster number 72 | ;; now dx - 0xXCCC for or 0xCCCX 73 | test al, 0x01 74 | jnz .odd 75 | and dx, 0x0FFF 76 | jmp .no_dif 77 | .odd: shr dx, 4 78 | .no_dif:mov ax, dx 79 | retn 80 | 81 | ;;; ;;;;;;;;;;;; Service routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 82 | 83 | ; ___________________________________________________________________ 84 | read_sectors: 85 | ;; args: 86 | ;; ax - num of sector 87 | ;; out: 88 | ;; CACHE_SEG:bx - cached image of sector 89 | call get_cache_of_sector 90 | jz .read 91 | retn 92 | 93 | .read: call cache_sectors 94 | retn 95 | 96 | ; ___________________________________________________________________ 97 | cache_sector: 98 | ;; args: 99 | ;; ax - sector logical address 100 | ;; cx - count of sectors 101 | ;; out: bx - pointer to cache of sector 102 | ;; find place for sectors 103 | 104 | retn 105 | 106 | ; ___________________________________________________________________ 107 | get_cache_of_sector: 108 | ;; args: 109 | ;; ax - sector num 110 | ;; out: 111 | ;; bx - pointer to cache at [CACHE_SEG:di] if cached 112 | ;; 0 and zf if no cached image 113 | pusha 114 | ;; enumerate chunks of cache: 115 | push es 116 | mov bx, CACHE_SEG 117 | mov es, bx 118 | mov bx, 0x0004 119 | .next_chunk: 120 | mov dx, word [es:bx-4] 121 | ;; 0th sector is never cached, so 122 | test dx, dx 123 | jz .no_cache 124 | ;; some cached chunk 125 | cmp dx, ax 126 | je .ret 127 | ;; go to next 128 | add bx, [bpb.BpS] 129 | cmp bx, CACHE_SIZE 130 | jl .next_chunk 131 | .no_cache: 132 | xor bx, bx 133 | .ret: pop es 134 | popa 135 | retn 136 | 137 | 138 | -------------------------------------------------------------------------------- /vga.inc: -------------------------------------------------------------------------------- 1 | ; 2 | ; VGA drawing routins 3 | ; (c) Dmytro Sirenko 4 | ; ___________________________________________________________________ 5 | %ifndef __VGA_INC 6 | %define __VGA_INC 7 | 8 | 9 | ;;; _________________________________________________________________ 10 | set_vga_mode: 11 | ;;// void set_vga_mode(al mode) 12 | xor ah, ah 13 | int 10h 14 | retn 15 | 16 | ;;; _________________________________________________________________ 17 | draw_pixel: 18 | ;;// void put_pixel(bx X, ax Y, cl color) 19 | cmp ax, 0 20 | jl .done 21 | cmp ax, VGA13h_MAX_Y 22 | jge .done 23 | cmp bx, 0 24 | jl .done 25 | cmp bx, VGA13h_MAX_X 26 | jge .done 27 | 28 | mov dx, 320 29 | mul dx 30 | add ax, bx 31 | mov di, ax 32 | mov byte [es:di], cl 33 | .done: retn 34 | 35 | ;;; _________________________________________________________________ 36 | draw_line: 37 | ;;// void put_line(si *point1, di *point2, al color) 38 | ;; point { dw x, y; } 39 | ;; whether is horisontal 40 | mov bx, word [di + 2] 41 | cmp bx, word [si + 2] 42 | jne .not_horisontal 43 | ;; draw horisontal line 44 | push es 45 | push ax ;; save color 46 | call get_pointer_for_xy ;; [si] -> ax 47 | 48 | mov cx, word [di] 49 | sub cx, word [si] 50 | jge .endif 51 | ;; df = 1, cx = abs(cx) 52 | std 53 | neg cx ;; cx > 0 54 | .endif: 55 | mov bx, VGAMEM_SEGM 56 | mov es, bx ;; es = 0xA000 57 | mov di, ax ;; stosb: al -> es:di until cx > 0 58 | pop ax ;; restore color 59 | rep stosb 60 | cld ;; clear DF if set 61 | pop es 62 | retn 63 | 64 | .not_horisontal: 65 | mov bx, word [di] 66 | cmp bx, word [si] 67 | jne .not_vertical 68 | ;; draw vertical line 69 | push ax 70 | mov cx, word [di + 2] 71 | sub cx, word [si + 2] 72 | call get_pointer_for_xy 73 | mov di, ax 74 | pop ax 75 | push es 76 | mov bx, VGAMEM_SEGM 77 | mov es, bx 78 | .next_vert: 79 | mov byte [es:di], al 80 | 81 | test cx, cx 82 | jns .dnup 83 | sub di, VGA13h_MAX_X 84 | inc cx 85 | jmp .eif 86 | .dnup: add di, VGA13h_MAX_X 87 | dec cx 88 | .eif: jnz .next_vert 89 | 90 | pop es 91 | retn 92 | 93 | .not_vertical: 94 | ;; anal magic... 95 | retn 96 | ;;; _________________________________________________________________ 97 | draw_rect: 98 | ;;// void draw_rect(si *p1, cx width, dx height, al color); 99 | 100 | push ax 101 | call get_pointer_for_xy 102 | mov di, ax ; now si - pointer to pixel di.x:di.y 103 | pop ax 104 | 105 | push es 106 | mov bx, VGAMEM_SEGM 107 | mov es, bx 108 | 109 | .next_line: 110 | push di 111 | push cx 112 | rep stosb 113 | pop cx 114 | pop di 115 | add di, VGA13h_MAX_X 116 | dec dx 117 | jnz .next_line 118 | 119 | pop es 120 | retn 121 | 122 | ; ___________________________________________________________________ 123 | get_pointer_for_xy: 124 | ;; args: si *point 125 | ;; out: ax pos, preserves other regs 126 | mov ax, word [si + 2] 127 | push dx 128 | mov dx, VGA13h_MAX_X 129 | mul dx 130 | add ax, word [si] 131 | pop dx 132 | retn 133 | 134 | ;;; _________________________________________________________________ 135 | vga_trial: 136 | ;;// void tetris(void) 137 | mov al, 13h 138 | call set_vga_mode 139 | 140 | mov ax, 20 141 | mov bx, 256 142 | push es 143 | ;; begin paint: 144 | push VGAMEM_SEGM 145 | pop es 146 | 147 | ;; draw line with all available colors 148 | .loop: 149 | mov cx, bx 150 | pusha 151 | call draw_pixel 152 | popa 153 | dec bx 154 | cmp bx, 0 155 | ja .loop 156 | pop es 157 | 158 | ;; draw rect 159 | mov cx, 20 160 | mov dx, 20 161 | mov al, 10 162 | mov si, .point1 163 | call draw_rect 164 | 165 | ;; draw line 166 | mov word [.point1], 120 167 | mov word [.point1 + 2], 60 168 | ;; point1 = (120, 60) 169 | mov si, .point1 170 | mov di, .point2 171 | mov al, 20 172 | call draw_line 173 | 174 | mov word [.point2], 120 175 | mov word [.point2 + 2], 50 176 | mov di, .point2 177 | mov si, .point1 178 | call draw_line 179 | 180 | call wait_key 181 | 182 | xor al, al 183 | call set_video_mode 184 | 185 | retn 186 | .point1 dw 50, 40 187 | .point2 dw 20, 60 188 | 189 | 190 | %endif 191 | --------------------------------------------------------------------------------