Compare commits

..

7 Commits

19 changed files with 591 additions and 207 deletions

BIN
.Makefile.swo Normal file

Binary file not shown.

2
.gitignore vendored
View File

@@ -1 +1,3 @@
*.swp
disk_images/*
tmp-loop/*

View File

@@ -4,26 +4,38 @@ SRC_DIR=source
BUILD_DIR=disk_images
DATA_DIR=data
# CD image
cdrom: $(BUILD_DIR)/crawos.iso
$(BUILD_DIR)/crawos.iso: floppy_image
mkdir -p disk_images
mkisofs -quiet -V 'CRAWOS' -input-charset iso8859-1 -o disk_images/crawos.iso -b crawos.img disk_images/
chmod 755 disk_images/*
chgrp users disk_images/*
# Floppy image
# Fat12
floppy_image: $(BUILD_DIR)/crawos.img
$(BUILD_DIR)/crawos.img: bootloader kernel
mkdir -p disk_images
dd if=/dev/zero of=$(BUILD_DIR)/crawos.img bs=512 count=2880 # Use dd to make a disk image
mkfs.fat -F 12 -n "CRAWOS" $(BUILD_DIR)/crawos.img # Format the disk image with fat12
dd if=$(BUILD_DIR)/boot.bin of=$(BUILD_DIR)/crawos.img conv=notrunc # Put boot.bin inside the disk image
mcopy -i $(BUILD_DIR)/crawos.img $(BUILD_DIR)/kernel.bin "::kernel.bin" # Put kernel.bin inside the disk image
for filename in $(DATA_DIR)/*; do mcopy -i $(BUILD_DIR)/crawos.img $$filename "::/$$(echo $$filename | xargs -n 1 basename)"; done
# Bootloader
bootloader: $(BUILD_DIR)/boot.bin
$(BUILD_DIR)/boot.bin:
mkdir -p disk_images
$(ASM) $(SRC_DIR)/bootload/boot.asm -f bin -o $ $(BUILD_DIR)/boot.bin
# Kernel
kernel: $(BUILD_DIR)/kernel.bin
$(BUILD_DIR)/kernel.bin:
mkdir -p disk_images
$(ASM) $(SRC_DIR)/kernel/kernel.asm -f bin -o $ $(BUILD_DIR)/kernel.bin
# Clean
clean:
rm -f disk-images/*
rm -f disk_images/*

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -5,27 +5,27 @@ jmp short main
nop
; Define Fat12 header
bdb_oem: db 'MSWIN4.1'
bdb_bytes_per_sector: dw 512
bdb_sectors_per_cluster: db 1
bdb_reserved_sectors: dw 1
bdb_fat_count: db 2
bdb_dir_entries_count: dw 0E0h
bdb_total_sectors: dw 2880
bdb_media_descriptor_type: db 0F0h
bdb_sectors_per_fat: dw 9
bdb_sectors_per_track: dw 18
bdb_heads: dw 2
bdb_hidden_sectors: dd 0
bdb_large_sector_count: dd 0
bdb_oem: db 'MSWIN4.1' ; ignore
bdb_bytes_per_sector: dw 200h ; = 512d
bdb_sectors_per_cluster: db 01h ; sector = cluster
bdb_reserved_sectors: dw 01h
bdb_fat_count: db 02h ; We've got a fat1 and fat2
bdb_dir_entries_count: dw 0E0h ; Maximum number of root directory entries
bdb_total_sectors: dw 0B40h ; = 2880d
bdb_media_descriptor_type: db 0F0h ; ignore
bdb_sectors_per_fat: dw 09h
bdb_sectors_per_track: dw 12h ; = 18d
bdb_number_of_heads: dw 02h ; top and bottom of the floppy disk
bdb_hidden_sectors: dd 0 ; ignore
bdb_large_sector_count: dd 0 ; total sector count for fat32 (0 for fat12 or fat16)
; extended boot record
ebr_drive_number: db 0
db 0
ebr_signature: db 29h
ebr_volume_id: db 12h, 34h, 56h, 78h
ebr_volume_label: db 'CrawShaw OS'
ebr_system_id: db 'FAT12 '
ebr_drive_number: db 0 ; ignore
db 0 ; ignore
ebr_signature: db 29h ; boot signature, indicates that the next three fields are present (0x29)
ebr_volume_id: db 12h, 34h, 56h, 78h ; unique id for volume tracking
ebr_volume_label: db 'CrawShaw OS' ; must be 11 bytes
ebr_system_id: db 'FAT12 ' ; must be 8 bytes
main:
; Setup registers
@@ -37,11 +37,11 @@ main:
mov sp, 7C00h
; Read from disk
;mov [ebr_drive_number], dl
;mov ax, 1
;mov cl, 1
;mov bx, 7E00h
;call disk_read
; mov [ebr_drive_number], dl
; mov ax, 1
; mov cl, 1
; mov bx, 7E00h
; call disk_read
; Output boot text
mov si, boot_text
@@ -54,46 +54,54 @@ main:
; root dir: gives location of data
; data: stores the actual data
; Get LBA of root dir
mov ax, [bdb_sectors_per_fat]
mov bl, [bdb_fat_count]
; Get LBA of root dir (sectors per fat * fat count) + number of reserved sectors
mov ax, [bdb_sectors_per_fat] ; ax = 09h
mov bl, [bdb_fat_count] ; bl = 02h
xor bh,bh ; clear bh
mul bx ; 9 * 2 = 18
add ax, [bdb_reserved_sectors] ; The LBA of root dir
mul bx ; ax*bx = sectors per fat * fat count = 09h * 02h = 18
add ax, [bdb_reserved_sectors] ; then add on the reserved sector (1) = The LBA of root dir = 19d = 13h
push ax ; Push to stack
; the top of the ax stack now stores the LBA of the root directory
mov ax, [bdb_dir_entries_count]
; determine the size of the root directory
mov ax, [bdb_dir_entries_count] ; move the number of root directory entries into ax (E0h)
shl ax,5 ; ax *= 32 (shifting 5 times)
xor dx,dx ; Clear dx
div word [bdb_bytes_per_sector] ;32*num of entries)/bytes per sector
xor dx,dx ; Clear dx (remainder)
div word [bdb_bytes_per_sector] ;(32*num of entries)/bytes per sector = total number of sectors we need to read
test dx,dx ; See if there's a remainder
jz root_dir_after
inc ax ; Add one if there's a remainder
inc ax ; Add one if there's a remainder (this is like rounding up)
; read the root directory tree into memory
root_dir_after:
; read the data from the root directory from disk
mov cl, al
pop ax ; LBA of root dir
mov dl, [ebr_drive_number]
mov bx, buffer
call disk_read
call disk_read ; convert the LBA of the root directory to a CHS
xor bx,bx ; clear bx
mov di, buffer ; Loaded root dir into memory
mov di, buffer ; Loaded root dir into memory, now we need to find the kernel
; di points to the start of this memory
; Search for 'KERNEL BIN' in a loop until all root files entries have been checked
search_for_kernel:
mov si, file_kernel_bin ; Move the name of the kernel into si
mov cx, 11
mov si, file_kernel_bin ; Move the name of the kernel into si (string pointer)
mov cx, 11 ; length of 'KERNEL BIN'
push di ; Preserve di
repe cmpsb ; Repeat a comparison of bytes between kernel name and current bytes until it finds a match
pop di ; Retrieve di
je found_kernel
add di, 32 ; Next directory entry
add di, 32 ; increment di to the next directory entry
inc bx
cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist
jl search_for_kernel ; Repeat search
jmp kernel_not_found ; If the last dir has been searched, then there is no kernel
; The kernel has not been found so output an error and halt
kernel_not_found:
mov si, kernel_load_error
call print_string
@@ -101,13 +109,15 @@ kernel_not_found:
hlt
jmp halt
; The kernel has been found
found_kernel:
mov si, kernel_found_text
call print_string
; Find kernel cluster
mov ax, [di+26]
mov ax, [di+26] ; di is the address of the kernel, 26 is the offset
mov [kernel_cluster], ax
; Setup registers for disk read
mov ax, [bdb_reserved_sectors]
mov bx, buffer
mov cl, [bdb_sectors_per_fat]
@@ -160,6 +170,8 @@ next_cluster_after:
jmp load_kernel_loop
read_finish: ; Load kernel
mov si, kernel_loading
call print_string
mov dl, [ebr_drive_number]
mov ax, kernel_load_segment
mov ds, ax
@@ -174,33 +186,65 @@ halt:
; LBA = index of data segment on disk
; CHS = cylinder, header, sector
; T = LBA/sectors per track
; S = (LBA%sectors per track) + 1
; H = T % heads
; C = T / headers
; input, LBA index: ax
; sector number: cx [0-5]
; cylinder: cx [6-15]
; sector number: cl
; cylinder: ch
; head: dh
; Example where LBA = 50h (CHS = 2,0,9)
; ax = 0050h, push this to the stack
; dx = 0000h
; dx = 50h % 12h = 0008h
; ax = 50h / 12h = 0004h
; dx = 0009h
; cx = 0009h
; dx = 0000h
; dx = 04h % 02h = 0000h
; ax = 04h / 02h = 0002h
; dh = 00h (dx = 0000h)
; ch = 02h (cx = 0209h)
; ah = 00h (ax = 0002h)
; cl = 09h OR 00h = 09h (cx = 0209h)
; ax = 0050h
; dl = 50h (dx = 0050h)
; ax = 0050h
; thus:
; cylinder (ch) = 02h
; head (cl) = 00h
; sector (dh) = 09h
lba_to_chs:
push ax
push dx
xor dx,dx ; clear dx
div word [bdb_sectors_per_track] ;(LBA % sectors per track) + 1 = sector
div word [bdb_sectors_per_track] ; (LBA % sectors per track) + 1 = sector
inc dx ; sector, dx stores the remainder so we increment that.
mov cx,dx
xor dx,dx ; clear dx
div word [bdb_heads]
div word [bdb_number_of_heads]
mov dh,dl ; head, dx stores remainder so we move that up 8 bits to dh
mov dh,dl ; head
mov ch,al
shl ah, 6
or CL, AH ; cylinder
shl ah, 6 ; * 32
or cl, ah ; cylinder
pop ax
mov dl,al
pop ax
RET
ret
; int 13h/ah = 02h read disk sectors into memory
; al = number of sectors to read
; ch = cylinder number
; cl = sector number
; dh = head number
; dl = drive number
; es:bx = points to data buffer
disk_read:
push ax
push bx
@@ -209,22 +253,32 @@ disk_read:
push di
call lba_to_chs
; cl = sector
; ch = cylinder
; dh = head
; dl = drive
call lba_to_chs ; Get the chs address
mov ah, 02h
mov ah, 02h ; BIOS ah code for read disk sectors to memory
; repeat drive read 3 times (incase of random error)
mov di, 3 ; counter
; This is basically
; for di in range(3,1,1):
; We test to see if we can read the disk 3 times
retry:
stc
; When the disk is tried to be read, the CF flag will be
; set if there's an error, so we just clear it to return it to
; the default state
stc ; sets the cf flag
int 13h
jnc done_read
jnc done_read ; jump if cf = 0
call disk_reset ; Reset drivers of disk
dec di
test di, di
dec di ; di -= 1
test di, di ; if di = 0
jnz retry
fail_disk_read:
@@ -233,6 +287,7 @@ fail_disk_read:
hlt
jmp halt
; int 13h / ah = 00h reset disk system
disk_reset:
pusha
mov ah, 0 ; Reset drive
@@ -280,14 +335,15 @@ print_string:
pop si
ret
boot_text: db '[OK] Boot sequence begun...', 0
kernel_found_text: db '[OK] Kernel located...', 0
disk_read_fail: db '[ERR] Failed to read disk!', 0
boot_text: db 'OK] Boot begun', 0
kernel_found_text: db 'OK] Kernel located', 0
kernel_loading: db 'OK] Loading kernel', 0
disk_read_fail: db 'ERR] Disk read fail', 0
file_kernel_bin: db 'KERNEL BIN' ; Must have a double space between KERNEL and BIN
kernel_load_error: db '[ERR] Kernel not found!', 0
kernel_load_error: db 'ERR] Kernel not found', 0
kernel_cluster: dw 0
kernel_load_segment: equ 2000h
kernel_load_segment: equ 2000h ; an area in memory we know should be available
kernel_load_offset: equ 0

View File

@@ -17,42 +17,48 @@ os_start_cli:
os_read_cli:
pusha
mov si, user_input
call os_upper_case ; Make the input uppercase so it's case insensitive
.output_the_user_input:
call os_print_newline
.check_matches: ; Check if the user input matches any internal commands
; Help
mov si, user_input
mov di, help_string
call os_compare_strings
cmp cl, 1
je help
; Clear screen
mov si, user_input
mov di, clear_string
call os_compare_strings
cmp cl, 1
je clear
; Reboot
mov si, user_input
mov di, reboot_string
call os_compare_strings
cmp cl, 1
je power_reboot
; Pong
mov si, user_input
mov di, pong_string
call os_compare_strings
cmp cl, 1
je pong
mov si, user_input
mov di, snake_string
call os_compare_strings
cmp cl, 1
je snake
jmp .unkown
.unkown:
mov si, unknown_command
call os_print_string
mov si, user_input
call os_print_string_nl
call os_print_string
jmp .finish
.finish:
@@ -65,26 +71,23 @@ clear:
help:
mov si, help_text
call os_print_string_nl
call os_print_string
call os_read_cli.finish
pong:
call game_pong
call os_read_cli.finish
snake:
call game_snake
call os_read_cli.finish
section .data
welcome_text db 'Welcome to CrawOS, the Cool, Real and AWsome Operating System', 0
welcome_text db 'Welcome to CrawOS, the Cwick, Real and AWsome Operating System\n', 0
user_input times 20 db 0
prompt_length db 20
prompt db 'CrawOS sh> ', 0
help_string db 'HELP', 0
clear_string db 'CLEAR', 0
reboot_string db 'REBOOT', 0
cat_string db 'CAT', 0
pong_string db 'PONG', 0
snake_string db 'SNAKE', 0
help_text db 'This is for Cowards: "HELP" for this help text, "CLEAR" to clear the screen, esc to reboot', 0
help_text db 'This is for Cowards:\n"HELP" for this helpful text,\n"CLEAR" to clear the screen,\n"REBOOT" or esc to reboot\n', 0
command_result_text db 'You typed: ', 0
unknown_command db 'Error: Unkown Command.. ', 0
unknown_command db 'Error: Unkown Command.. \n', 0

View File

@@ -0,0 +1,175 @@
; Reset the disk system using int 13h / AH = 00h
disk_reset:
pusha
stc
mov ah, 00h
int 13h
popa
ret
; ------------------------------------
; Load the root directory into memory (into disk_buffer which is 24000h)
disk_load_root:
pusha
mov ax, 19 ; First sector of root entry
call math_lba_to_chs ; Assigns ch, cl and dh the correct values
xor ax,ax
mov dl, [ebr_drive_number] ; Drive number
mov ah, 02h ; BIOS ah code for read disk sectors to memory
mov al, 0Ch ; Root directory has 12 sectors
mov si, root_buffer ; ES:BX should point to our buffer
mov bx, si
; repeat drive read 3 times (incase of random error)
mov di, 3 ; counter
; This is basically
; for di in range(3,1,1):
; We test to see if we can read the disk 3 times
.try_read_disk: ; Try read the floppy three times
; When the disk is tried to be read, the CF flag will be
; set if there's an error, so we just clear it to return it to
; the default state
stc ; sets the cf flag
int 13h
jnc .done_read ; jump if cf = 0
call disk_reset ; Reset drivers of disk
dec di ; di -= 1
test di, di ; if di = 0
jnz .try_read_disk
jmp .disk_error
.disk_error:
mov si, disk_read_fail
call os_print_string
popa
ret
.done_read:
popa
ret
; ---------------------------------------------
; Reads a certain number of sectors into memory
; int 13h/ah = 02h read disk sectors into memory
; al = number of sectors to read
; ch = cylinder number
; cl = sector number
; dh = head number
; dl = drive number
; es:bx = points to data buffer
disk_read:
push ax
push bx
push cx
push dx
push di
; cl = sector
; ch = cylinder
; dh = head
; dl = drive
call math_lba_to_chs ; Get the chs address
mov ah, 02h ; BIOS ah code for read disk sectors to memory
; repeat drive read 3 times (incase of random error)
mov di, 3 ; counter
; This is basically
; for di in range(3,1,1):
; We test to see if we can read the disk 3 times
.retry:
; When the disk is tried to be read, the CF flag will be
; set if there's an error, so we just clear it to return it to
; the default state
stc ; sets the cf flag
int 13h
jnc .done_read ; jump if cf = 0
call .disk_reset ; Reset drivers of disk
dec di ; di -= 1
test di, di ; if di = 0
jnz .retry
.fail_disk_read:
pop di
pop dx
pop cx
pop bx
pop ax
ret
; int 13h / ah = 00h reset disk system
.disk_reset:
pusha
mov ah, 0 ; Reset drive
stc
int 13h
jc .fail_disk_read
popa
ret
.done_read:
pop di
pop dx
pop cx
pop bx
pop ax
ret
; -------------------------------------
disk_load_file:
pusha
mov di, fat12_file_name
call os_format_fat_filename
; Prepare values
mov si, root_buffer
xor bx,bx
.search_root:
mov di, fat12_file_name ; Move the name of the kernel into di
mov cx, 11 ; length of 'KERNEL BIN'
push si ; Preserve si
repe cmpsb ; Repeat a comparison of bytes between file name and current bytes until it finds a match
pop si ; Retrieve si
je .found_file
add si, 32 ; increment di to the next directory entry
inc bx
cmp bx, [bdb_dir_entries_count] ; Have we reached the number of directories that exist
jl .search_root ; Repeat search
jmp .file_not_found ; If the last dir has been searched, then there is no kernel
.found_file:
mov ax, [si+26] ; ax is now a pointer to the pointer to the file relative to the data segments :D
add ax, 20h
mov [file_cluster], ax
; Setup registers for disk read
mov bx, data_buffer
mov dl, [ebr_drive_number]
call disk_read ; Load file from disk into memory
jmp .done
.file_not_found:
mov si, file_not_found
call os_print_string
jmp .done
.done:
popa
ret
section .data:
disk_read_fail: db 'Error: Could not read disk\n', 0
file_not_found: db 'File not found\n', 0
file_found: db 'File found\n', 0
loading_root: db 'Loading root diretory\n', 0
file_cluster: dw 0
fat12_file_name: db ' '

View File

@@ -43,7 +43,7 @@ os_display_input:
jmp .check_key_pressed
.esc_key:
call os_reboot
call power_reboot
.enter_key:
mov al, 0

View File

@@ -0,0 +1,54 @@
; LBA = index of data segment on disk
; CHS = cylinder, header, sector
; T = LBA/sectors per track
; S = (LBA%sectors per track) + 1
; H = T % heads
; C = T / headers
; input, LBA index: ax
; ouput:
; sector number: cl
; cylinder: ch
; head: dh
; Example where LBA = 50h (CHS = 2,0,9)
; ax = 0050h, push this to the stack
; dx = 0000h
; dx = 50h % 12h = 0008h
; ax = 50h / 12h = 0004h
; dx = 0009h
; cx = 0009h
; dx = 0000h
; dx = 04h % 02h = 0000h
; ax = 04h / 02h = 0002h
; dh = 00h (dx = 0000h)
; ch = 02h (cx = 0209h)
; ah = 00h (ax = 0002h)
; cl = 09h OR 00h = 09h (cx = 0209h)
; ax = 0050h
; dl = 50h (dx = 0050h)
; ax = 0050h
; thus:
; cylinder (ch) = 02h
; head (cl) = 00h
; sector (dh) = 09h
math_lba_to_chs:
push ax
push dx
xor dx,dx ; clear dx
div word [bdb_sectors_per_track] ; (LBA % sectors per track) + 1 = sector
inc dx ; sector, dx stores the remainder so we increment that.
mov cx,dx
xor dx,dx ; clear dx
div word [bdb_number_of_heads]
mov dh,dl ; head, dx stores remainder so we move that up 8 bits to dh
mov ch,al
shl ah, 6 ; * 32
or cl, ah ; cylinder
pop ax
mov dl,al
pop ax
ret

View File

@@ -1,6 +1,9 @@
os_reboot:
power_reboot:
mov ax, 0x5307
mov bx, 0x0001
mov cx, 0x0003
int 0x19
; Not done
power_shutdown:
ret

View File

@@ -6,21 +6,125 @@
; memory address 2: |s|n|a|k|e|0|
; ^
; SI => lodsb loads value stored at SI to AX and then increments SI if DF is 0
; Additionaly, if the di string ends and the relevant character in si contains a space, it will still return
; the strings as being equal, this is to allow for command line arquments
os_compare_strings:
cld
.compare:
mov al, 0
scasb
je .di_ended
dec di
lodsb
scasb ; Compare di to si
jne .unequal ; If they are no equal, jump to .unequal
cmp al, 0 ; Check if string is finished
je .equal ; If it has, return true
jne .unequal ; If they are not equal, jump to .unequal
jmp .compare ; Finally, repeat
.unequal:
mov cl, 0 ; Change to 0 if unquality is proven
ret
.di_ended:
lodsb
cmp al, 20h ; 20h = space
je .equal
cmp al, 0
je .equal
jmp .unequal
.equal:
mov cl, 1
ret
; Get the length of a string
; 'hello world', 0 is 11 characters long (excluding the terminator)
; input: si points to the string to be counted
; output: cl holds the length
os_string_length:
push si
xor cl,cl ; Clear the al register
.loop:
lodsb
cmp al, 0
je .finish
inc cl
jmp .loop
.finish:
pop si
ret
; convert a string to fat's filename format
; It will be capitalised and 11 characters long,
; 8 for the filename, 3 for the extension
; eg: 'file.txt' -> 'FILE TXT'
; input: si points to filename, di points to a free 11 bytes in memory
; output: di points to the fat formatted filename
os_format_fat_filename:
pusha
call os_upper_case
call os_string_length ; Stores the length of the string in cl
mov bl, 11
sub bl, cl ; 11 - string_length
.character_loop:
lodsb
cmp al, 0
je .finish
cmp al, 2Eh ; 2Eh
je .add_spaces ; This will end up back at .character_loop
stosb
jmp .character_loop
.add_spaces: ; Add the number of spaces as bl holds
mov al, ' ' ; 20h = space
.spaces_loop:
stosb
cmp bl, 0
je .character_loop
dec bl
jmp .spaces_loop
.finish:
popa
ret
; Convert a string to all upper/lower case
; INPUT: si pointing to a string
; OUPUT: the same string in memory will now be capitalised/decapitalised
os_upper_case: ; to upper case
pusha
mov di, si
.loop:
lodsb ; Load the character into al
inc di
cmp al, 0
je .finish ; If it's null then the string is finished
cmp al, 7Ah ; 7Ah = 'z'
jns .loop ; Ignore if it's more than 'z'
cmp al, 61h ; 61h = 'a'
js .loop ; Ignore if it's less than 'a'
sub al, 20h ; Otherwise subtract 20h to capitalise it
dec di
stosb ; Store the new value
jmp .loop ; Next character
.finish:
popa
ret
os_lower_case: ; to lower case
pusha
mov di, si
.loop:
lodsb ; Load the character into al
inc di
cmp al, 0
je .finish ; If it's null then the string is finished
cmp al, 5Ah ; 5Ah = 'Z'
jns .loop ; Ignore if it's more than 'Z'
cmp al, 41h ; 41h = 'A'
js .loop ; Ignore if it's less than 'A'
add al, 20h ; Otherwise subtract 20h to capitalise it
dec di
stosb ; Store the new value
jmp .loop ; Next character
.finish:
popa
ret

View File

@@ -1,4 +1,7 @@
; SI = pointer to start of string to be printed
; \n for newline
; \t for tab
; \\ for a single backslash
os_print_string:
pusha
@@ -8,34 +11,68 @@ os_print_string:
lodsb ; Get char from si into al
cmp al, 0 ; Compare al to 0
je .done ; If char is zero, end of string
cmp al, 5Ch ; backslash
je .backslash
int 10h ; Otherwise, print it
jmp .repeat ; And move on to next char
.backslash: ; If there is a '\', do what it says, \n for newline, \t for tab etc
lodsb
dec si
cmp al, 6Eh ; 'n'
je .newline
cmp al, 74h ; \t
je .tab
cmp al, 5Ch ; '\'
je .another_backslash
jmp .repeat
.newline:
mov al, 0Ah ; new line
int 10h
mov al, 0Dh ; carriage return
int 10h
jmp .finish_backslash
.tab:
mov al, 09h ; tab
int 10h
jmp .finish_backslash
.another_backslash: ; This just prints 1 backslash
mov al, 5Ch
int 10h
jmp .finish_backslash
.finish_backslash:
inc si
jmp .repeat
.done:
popa
ret
; Exact same as the above procedure, but this adds a newline
; after priting, similar to the difference between Rust's print! and println!
os_print_string_nl:
; This is similar to the previous, however it prints
; raw output (including null) and prints the number
; of character defined by ax
; IN:
; SI = pointer to start of string to be printed
; AX = Length of string to print
text_raw_output:
pusha
mov di, ax
mov ah, 0Eh ; int 10h teletype function, we're telling the BIOS we will print something
.repeat:
lodsb ; Get char from si into al
cmp al, 0 ; Compare al to 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat ; And move on to next char
dec di
cmp di, 00h
je .done
jne .repeat
.done:
call os_print_newline
popa
ret
; --------------------------------------------
os_print_newline:

View File

@@ -48,24 +48,24 @@ game_pong:
mov dx, [p1_y]
sub dx, 5
mov [p1_y], dx
jmp .detect_input
ret
.p1_down:
mov dx, [p1_y]
add dx, 5
mov [p1_y], dx
jmp .detect_input
ret
; Player 2 movements
.p2_up:
mov dx, [p2_y]
sub dx, 5
mov [p2_y], dx
jmp .detect_input
ret
.p2_down:
mov dx, [p2_y]
add dx, 5
mov [p2_y], dx
jmp .detect_input
ret
; Ball bouncing
; This should move the ball along one frame
@@ -97,17 +97,17 @@ game_pong:
; Player 1
cmp al, 77h ; Pressed 'w' (player 1 up)
je .p1_up
call .p1_up
cmp al, 73h ; Pressed 's' (player 1 down)
je .p1_down
call .p1_down
; Player 2
cmp al, 5bh ; Pressed '[' (player 2 up)
je .p2_up
call .p2_up
cmp al, 27h ; Pressed ''' (player 2 down)
je .p2_down
call .p2_down
call .bounce_ball
;call .bounce_ball
call .draw_screen
jmp .detect_input

View File

@@ -1,94 +0,0 @@
game_snake:
call .draw_screen
call .detect_input
.draw_screen:
call os_set_graphics_mode ; Clear screen
.draw_snake_loop:
mov ax, [snake_x]
mov [x_start], ax
mov [x_end], ax
mov bx, [snake_y]
mov [y_start], bx
mov [y_end], bx
call os_draw_graphical_rectangle
ret
; Player 1 movements
.up:
mov dword [snake_direction], 0
jmp .end_detect_input
.down:
mov dword [snake_direction], 2
jmp .end_detect_input
.left:
mov dword [snake_direction], 3
jmp .end_detect_input
.right:
mov dword [snake_direction], 1
jmp .end_detect_input
.move_up:
mov dx, [snake_y]
sub dx, 1
mov [snake_y], dx
ret
.move_down:
mov dx, [snake_y]
add dx, 1
mov [snake_y], dx
ret
.move_left:
mov dx, [snake_x]
sub dx, 1
mov [snake_x], dx
ret
.move_right:
mov dx, [snake_x]
add dx, 1
mov [snake_x], dx
ret
.move_snake:
cmp dword [snake_direction], 0
je .move_up
cmp dword [snake_direction], 1
je .move_right
cmp dword [snake_direction], 2
je .move_down
; Else it must be left
jmp .move_left
.detect_input:
call os_read_input
cmp al, 08h
je .finish
; Player 1
cmp al, 77h ; Pressed 'w' up
je .up
cmp al, 61h ; Pressed 'a' left
je .left
cmp al, 73h ; Pressed 's' down
je .down
cmp al, 64h ; Pressed 'd' right
je .right
.end_detect_input:
call .move_snake
call .draw_screen
jmp .detect_input
.finish:
call os_set_text_mode
call os_start_cli
section .data:
snake_x: dw 5
snake_y: dw 5
snake_direction: dw 1 ; 0=up, 1=right, 2=down, 3=left
snake_length: dw 1

View File

@@ -1,12 +1,17 @@
ORG 0h
ORG 00h
BITS 16
root_buffer equ 24000h
data_buffer equ 26000h
start:
mov si, boot_message
call os_print_string_nl
call os_print_string
mov si, help_text
call os_print_string_nl
call disk_load_root ; Loads the root directory into disk_buffer
; Physical address = (segment * 16) + offset
mov si, file_name
call disk_load_file
call os_start_cli
hlt
@@ -14,7 +19,31 @@ start:
halt:
jmp halt
boot_message: db 0Dh, 'Welcome to CrawOS!', 0Dh, 0
boot_message: db 'OK] Kernel successfully loaded!\n\n', 0
file_name: db 'hello.cws', 0
; Define Fat12 header
bdb_oem: db 'MSWIN4.1' ; ignore
bdb_bytes_per_sector: dw 200h ; = 512d
bdb_sectors_per_cluster: db 01h ; sector = cluster
bdb_reserved_sectors: dw 01h
bdb_fat_count: db 02h ; We've got a fat1 and fat2
bdb_dir_entries_count: dw 0E0h ; Maximum number of root directory entries
bdb_total_sectors: dw 0B40h ; = 2880d
bdb_media_descriptor_type: db 0F0h ; ignore
bdb_sectors_per_fat: dw 09h
bdb_sectors_per_track: dw 12h ; = 18d
bdb_number_of_heads: dw 02h ; top and bottom of the floppy disk
bdb_hidden_sectors: dd 0 ; ignore
bdb_large_sector_count: dd 0 ; total sector count for fat32 (0 for fat12 or fat16)
; extended boot record
ebr_drive_number: db 0 ; ignore
db 0 ; ignore
ebr_signature: db 29h ; boot signature, indicates that the next three fields are present (0x29)
ebr_volume_id: db 12h, 34h, 56h, 78h ; unique id for volume tracking
ebr_volume_label: db 'CrawShaw OS' ; must be 11 bytes
ebr_system_id: db 'FAT12 ' ; must be 8 bytes
; ------------------------------------------------------------------
; FEATURES -- Code to pull into the kernel
@@ -24,9 +53,9 @@ boot_message: db 0Dh, 'Welcome to CrawOS!', 0Dh, 0
%INCLUDE "source/kernel/features/power.asm"
%INCLUDE "source/kernel/features/strings.asm"
%INCLUDE "source/kernel/features/graphics.asm"
%INCLUDE "source/kernel/features/sound.asm"
%INCLUDE "source/kernel/features/basic.asm"
%INCLUDE "source/kernel/features/disk.asm"
%INCLUDE "source/kernel/features/math.asm"
; GAMES -- Games that I wrote for it
%INCLUDE "source/kernel/games/pong.asm"
%INCLUDE "source/kernel/games/snake.asm"

View File

@@ -1,6 +1,9 @@
#!/bin/sh
# This script starts the QEMU PC emulator, booting from the
# MikeOS floppy disk image
qemu-system-i386 -soundhw pcspk -drive format=raw,file=disk_images/mikeos.flp,index=0,if=floppy
make clean
sudo make
sudo chown $(whoami) disk_images/*
qemu-system-i386\
-drive file=disk_images/crawos.img,if=floppy,format=raw\
-m 512m\
-object memory-backend-file,id=pc.ram,size=512m,mem-path=/dev/shm/qemu-ram,share=on -machine memory-backend=pc.ram\
$1 $2