So I'm pretty new to operating system development. I've just worked on it for around half a year. My project is to make a Graphics OS in 16-bit Real Mode and Text Mode, while supporting file access using FAT12. I'm working on this on Windows XP x86 running in VirtualBox on a Windows 10 host. And to run the OS I run a virtualbox inside Windows XP with a floppy image.
I will start with posting my code (you might recognize alot of this code from MikeOS as I watched a Tinker Nut video showing this).
boot.asm
Code: Select all
BITS 16
jmp short boot_start ; Jump past disk description
nop ; Disk description has to be at index 3, so we add this.
; Disk description table, this makes it a valid floppy
OEMLabel db "KIRDBOOT" ; Disk label
BytesPerSector dw 512 ; Bytes per sector
SectorsPerCluster db 1 ; Sectors per cluster
ReservedForBoot dw 1 ; Reserved sectors for the boot record
NumberOfFats db 2 ; Numbers of copies of the FAT
RootDirEntries dw 224 ; Number of entries in root dir
LogicalSectors dw 2880 ; Number of logical sectors
MediumByte db 0F0h ; Medium descriptor byte
SectorsPerFat dw 9 ; Sectors per FAT
SectorsPerTrack dw 18 ; Sectors per track
Sides dw 2 ; Number of sides/heads
HiddenSectors dd 0 ; Number of hidden sectors
LargeSectors dd 0 ; Number of LBA sectors
DriveNo dw 0 ; Drive No: 0
Signature db 41 ; Drive signature: 41 for floppy
VolumeID dd 0x2F987802 ; Volume ID: any number
VolumeLabel db "KIRDOS " ; Volume Label: any 11 chars
FileSystem db "FAT12 " ; File system type: don't change!
; ---------------------------------------------------------------
; Main bootloader code
boot_start:
mov ax, 07C0h ; Set up 4K of stack space above buffer
add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
cli ; Disable interrupts while changing stack
mov ss, ax
mov sp, 4096
sti ; Restore interrupts
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
; NOTE: A few early BIOSes are reported to improperly set DL
cmp dl, 0
je no_change
mov [bootdev], dl ; Save boot device number
mov ah, 8 ; Get dribe parameters
int 13h
jc fatal_disk_error
and cx, 3Fh ; Maximum sector number
mov [SectorsPerTrack], cx ; Sector numbers start at 1
movzx dx, dh ; Maximum head number
add dx, 1 ; Head numbers start at 0 - add 1 for total
mov [Sides], dx
no_change:
mov eax, 0 ; Needed for some older BIOSes
; First we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33
floppy_ok: ; Ready to read first block of data
mov ax, 19 ; Root dir starts at logical sector 19
call l2hts
mov si, buffer ; Set ES:BX to point to our buffer (see end of code)
mov bx, ds
mov es, bx
mov bx, si
mov ah, 2 ; Params for int 13h: read floppy sectors
mov al, 14 ; And read 14 of them
pusha ; Prepare to enter loop
read_root_dir:
popa ; In case registers are altered by int 13h
pusha
stc ; A few BIOSes do not set properly on error
int 13h ; Read sectors using BIOS
jnc search_dir ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_root_dir ; Floppy reset OK?
jmp reboot ; If not, fatal double error
search_dir:
popa
mov ax, ds ; Root dir is now in [buffer]
mov es, ax ; Set DI to this info
mov di, buffer
mov cx, word [RootDirEntries] ; Search all (224) entries
mov ax, 0 ; Searching at offset 0
next_root_entry:
xchg cx, dx ; We use CX in the inner loop...
mov si, kern_filename ; Start searching for kernel filename
mov cx, 11
rep cmpsb
je found_file_to_load ; Pointer DI will be at offset 11
add ax, 32 ; Bumb searched entries by 1 (32 bytes per entry)
mov di, buffer ; Point to next entry
add di, ax
xchg dx, cx ; Get the original CX back
loop next_root_entry
mov si, file_not_found ; If kernel is not found, bail out
call print_string
jmp reboot
found_file_to_load: ; Fetch cluster and load FAT into RAM
mov ax, word [es:di+0Fh] ; Offset 11 + 15 = 26, contains 1st cluster
mov word [cluster], ax
mov ax, 1 ; Sector 1 = first sector of first FAT
call l2hts
mov di, buffer ; ES:BX points to our buffer
mov bx, di
mov ah, 2 ; int 13h params: read (FAT) sectors
mov al, 9 ; All 9 sectors of 1st FAT
pusha ; Prepare to enter loop
read_fat:
popa ; In case registers are altered by int 13h
pusha
stc
int 13h ; Read sectors using the BIOS
jnc read_fat_ok ; If read went OK, skip ahead
call reset_floppy ; Otherwise, reset floppy controller and try again
jnc read_fat ; Floppy reset OK?
; ***************************************************************
fatal_disk_error:
; ***************************************************************
mov si, disk_error ; If not, print error message and reboot
call print_string
jmp reboot ; Fatal double error
read_fat_ok:
popa
mov ax, 2000h ; Segment where we'll load the kernel
mov es, ax
mov bx, 0
mov ah, 2 ; int 13h floppy read params
mov al, 1
push ax ; Save in case we (or int calls) lose it
; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
; = (cluster number) + 31
load_file_sector:
mov ax, word [cluster] ; Convert sector to logical
add ax, 31
call l2hts ; Make appropriate params for int 13h
mov ax, 2000h ; Set buffer past what we've already read
mov es, ax
mov bx, word [pointer]
pop ax ; Save in case we (or int calls) lose it
push ax
stc
int 13h
jnc calculate_next_cluster ; If there's no error....
call reset_floppy ; Otherwise, reset floppy and retry
jmp load_file_sector
; In the FAT, cluster values are stored in 12 bits, so we have to
; do a bit of maths to work out whether we're dealing with a byte
; and 4 bits of the next byte -- or the last 4 bits of one byte
; and then the subsequent byte!
calculate_next_cluster:
mov ax, [cluster]
mov dx, 0
mov bx, 3
mul bx
mov bx, 2
div bx ; DX = [cluster] mod 2
mov si, buffer
add si, ax ; AX = word in FAT for the 12 bit entry
mov ax, word [ds:si]
or dx, dx ; If DX = 0 [cluster] is even; if DX = 1 then it's odd
jz even ; If [cluster] is even, drop last 4 bits of word
; with next cluster; if odd, drop first 4 bits
odd:
shr ax, 4 ; Shift out first 4 bits (they belong to another entry)
jmp short next_cluster_cont
even:
and ax, 0FFFh ; Mast out final 4 bits
next_cluster_cont:
mov word [cluster], ax ; Store cluster
cmp ax, 0FF8h ; FF8h = end of file marker in FAT12
jae end
add word [pointer], 512 ; Increase buffer pointer 1 sector length
jmp load_file_sector
end: ; We've got the file to load!
pop ax ; Clean up the stack (AX was pushed earlier)
mov dl, byte [bootdev] ; Provide kernel with boot device info
jmp 2000h:0000h ; Jump to entry point of loaded kernel!
; ---------------------------------------------------------------
; BOOTLOADER SUBROUTINES
reboot:
mov ax, 0
int 16h ; Wait for keystroke
mov ax, 0
int 19h ; Reboot the system
print_string: ; Output string in SI to screen
pusha
mov ah, 0Eh ; int 10h teletype function
.repeat:
lodsb ; Get char from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp short .repeat
.done:
popa
ret
reset_floppy: ; IN: [bootdev] = boot device; OUT: carry set on error
push ax
push dx
mov ax, 0
mov dl, byte [bootdev]
stc
int 13h
pop dx
pop ax
ret
l2hts: ; Calculate head, track and sector settings for int 13h
; IN: logical sector in AX, OUT: correct registers for int 13h
push bx
push ax
mov bx, ax ; Save logical sector
mov dx, 0 ; First the sector
div word [SectorsPerTrack]
add dl, 01h ; Physical sectors start at 1
mov cl, dl ; Sectors belong in CL for int 13h
mov ax, bx
mov dx, 0 ; Now calculate the head
div word [SectorsPerTrack]
mov dx, 0
div word [Sides]
mov dh, dl ; Head/side
mov ch, al ; Track
pop ax
pop bx
mov dl, byte [bootdev] ; Set correct device
ret
; ---------------------------------------------------------------
; STRINGS AND VARIABLES
kern_filename db "KRNLDR SYS" ; KirdOS kernel filename
disk_error db "Floppy error! Press any key...", 0
file_not_found db "KRNLDR.SYS not found!", 0
bootdev db 0 ; Boot device number
cluster dw 0 ; Cluster of the file we want to load
pointer dw 0 ; Pointer into Buffer, for loading kernel
; ---------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START
times 510-($-$$) db 0 ; Pad remainter of boot sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
buffer: ; Disk buffer begins (8k after this, stack starts)
; ===============================================================
Code: Select all
BITS 16
%DEFINE OS_VER '0.2.0.1' ; OS version number
%DEFINE OS_NAME 'KirdOS'
disk_buffer equ 24576
os_call_vectors:
jmp os_main ; 0000h -- Called from bootloader
jmp os_print_string ; 0003h
jmp os_clear_screen ; 0006h
jmp os_move_cursor ; 0009h
jmp os_get_cursor_pos ; 000Ch
jmp os_show_cursor ; 000Fh
jmp os_hide_cursor ; 0012h
jmp os_print_newline ; 0015h
jmp os_get_file_list ; 0018h
jmp os_string_length ; 001Bh
jmp os_string_reverse ; 001Eh
jmp os_string_uppercase ; 0021h
jmp os_string_lowercase ; 0024h
jmp os_string_compare ; 0027h
jmp os_seed_random ; 002Ah
jmp os_get_random ; 002Dh
jmp os_pause ; 0030h
jmp os_fatal_error ; 0033h
jmp os_wait_for_key ; 0036h
jmp os_check_for_key ; 0039h
jmp os_get_line ; 003Ch
jmp os_files_count ; 003Fh
; ---------------------------------------------------------------
; START OF KERNEL CODE
os_main:
cli ; Clear interrupts
mov ax, 0
mov ss, ax ; Set stack segment and pointer
mov sp, 0FFFFh
sti ; Restore interrupts
cld
mov ax, 2000h ; Sets segments to match kernel location in RAM
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
cmp dl, 0
je no_change
mov [bootdev], dl ; Save boot device number
push es
mov ah, 8 ; Get drive parameters
int 13h
pop es
and cx, 3Fh ; Maximum sector number
mov [SecsPerTrack], cx ; Sectors number start at 1
movzx dx, dh ; Maximum head humber
add dx, 1 ; Head numbers start at 0 - add 1 for total
mov [Sides], dx
no_change:
mov ax, 1003h ; Set text output with certain attributes
mov bx, 0 ; to be bright, and not blinking
int 10h
call os_seed_random
mov si, win_msg_none
mov word [win_msg], si
jmp main_loop
main_loop:
call os_clear_screen
call os_draw_screen
jmp .main_loop_pause
.main_loop_keys:
call os_wait_for_key
cmp ax, 0
jg .check_key
.main_loop_pause:
mov ax, 5
call os_pause
jmp .main_loop_keys
.check_key:
mov dl, byte [var_win_id]
cmp dl, 1
je .ck_apps
cmp dl, 3
je .ck_shutdown
.ck_home:
cmp al, '1'
je .cmd_apps
cmp al, '2'
je .cmd_terminal
cmp al, '3'
je .cmd_shutdown
.ck_done:
jmp main_loop
.ck_apps:
cmp ah, KEY_UP
je .ckapps_up
cmp ah, KEY_DOWN
je .ckapps_down
cmp ah, KEY_ENTER
je .ckapps_enter
cmp ah, KEY_RETURN
je .ckapps_enter
jmp main_loop
.ck_shutdown:
jmp main_loop
.cmd_apps:
mov byte [var_win_id], 1
jmp main_loop
.cmd_terminal:
mov byte [var_win_id], 0
jmp main_loop
.cmd_shutdown:
mov byte [var_win_id], 3
jmp main_loop
.ckapps_up:
mov cx, word [var_app_index]
dec cx
cmp cx, 0
jl .ckapps_up_l
mov word [var_app_index], cx
jmp main_loop
.ckapps_up_l:
call os_files_count
dec ax
mov word [var_app_index], ax
jmp main_loop
.ckapps_down:
mov cx, word [var_app_index]
inc cx
call os_files_count
cmp cx, ax
jge .ckapps_down_g
mov word [var_app_index], cx
jmp main_loop
.ckapps_down_g:
mov cx, 0
mov word [var_app_index], cx
jmp main_loop
.ckapps_enter:
mov cx, word [var_app_index]
mov ax, .buffer
call os_get_file_list
mov si, .buffer
mov di, .filename
.ckapps_more:
lodsb
cmp cx, 0
je .ckapps_store
cmp al, ','
jne .ckapps_more
dec cx
jmp .ckapps_more
.ckapps_store:
cmp al, ','
je .ckapps_load
stosb
jmp .ckapps_more
.ckapps_load:
mov si, .filename
call os_file_exists
jnc .not_found
mov si, .filename
mov di, kern_file_name
call os_string_compare
jc .no_kernel_execute
push si
mov bx, si
mov ax, si
call os_string_length
mov si, bx
add si, ax
dec si
dec si
dec si
mov di, bin_ext
mov cx, 3
rep cmpsb
jne .not_bin_extension
pop si
mov ax, si
mov cx, 32768
call os_load_file
jmp .execute_bin_program
.not_found:
call os_clear_screen
mov si, no_file_found
call os_print_string
call os_wait_for_key
jmp main_loop
.no_kernel_execute:
mov si, kernexec_warn_msg
call os_print_string
mov si, press_any_key_msg
call os_print_string
call os_wait_for_key
jmp main_loop
.not_bin_extension:
pop si
mov si, binonly_msg
call os_print_string
mov si, press_any_key_msg
call os_print_string
call os_wait_for_key
jmp main_loop
.execute_bin_program:
call os_clear_screen ; Clear screen before running
mov ax, 0
mov bx, 0
mov cx, 0
mov dx, 0
mov si, 0
mov di, 0
call 32768 ; Run the program. Program must end with 'ret'
call os_clear_screen
jmp main_loop
.filename times 13 db 0
.buffer times 1024 db 0
testdbg:
jmp 0003h
clear_reg:
mov ax, 0
mov bx, 0
mov cx, 0
mov dx, 0
mov si, 0
mov di, 0
ret
app_selector:
popa
mov si, os_init_msg
call os_print_string
call os_print_newline
mov si, os_version_msg
call os_print_string
call os_print_newline
call os_draw_screen
jmp $
file_selector:
pusha
mov word [.filename], 0
mov ax, .buffer ; Get comma-separated list of filenames
call os_get_file_list
mov si, .files_str
call os_print_string
mov si, .buffer
call os_print_string
call os_print_newline
mov si, .enter_file
call os_print_string
mov si, buffer
call os_get_line
mov si, buffer
mov ax, buffer
call os_string_length
call os_int_to_string
mov si, ax
call os_print_string
call os_print_newline
mov si, buffer
call os_file_exists
jnc .not_found
mov si, buffer ; Did the user try to run 'KRNLDR.SYS'?
mov di, kern_file_name
call os_string_compare
jc no_kernel_execute ; Show an error message if so
push si ; Save filename temporarily
mov bx, si
mov ax, si
call os_string_length
mov si, bx
add si, ax ; SI not points to end of filename...
dec si
dec si
dec si ; ...and now to start of extension!
mov di, bin_ext
mov cx, 3
rep cmpsb ; Are final 3 chars 'BIN'?
jne not_bin_extension ; If not, ask again
pop si ; Restore filename
mov ax, si
mov cx, 32768 ; Where to load the program file
call os_load_file ; Load filename prnted by AX
jmp execute_bin_program
.not_found:
call os_clear_screen
mov si, no_file_found
call os_print_string
jmp file_selector
.filename times 12 db 0
.buffer times 1024 db 0
.sbuffer times 64 db 0
.char_print db 0
.files_str db "Files on disk: ", 0
.enter_file db "Execute program: ", 0
execute_bin_program:
call os_clear_screen ; Clear screen before running
mov ax, 0 ; Clear all registers
mov bx, 0
mov cx, 0
mov dx, 0
mov si, 0
mov di, 0
call 32768 ; Call the extenral program code
; Loaded at second 32K segment
; (program mus end with 'ret')
call os_clear_screen ; When finished, clear screen
jmp app_selector ; and go back to the program list
no_kernel_execute: ; Warn about trying to executring kernel!
mov si, kernexec_warn_msg
call os_print_string
mov si, press_any_key_msg
call os_print_string
push ax
call os_wait_for_key
pop ax
jmp app_selector
not_bin_extension:
mov si, binonly_msg
call os_print_string
mov si, press_any_key_msg
call os_print_string
push ax
call os_wait_for_key
pop ax
jmp app_selector
; ---------------------------------------------------------------
; SYSTEM VARIABLES -- Settings for programs and system calls
kernexec_warn_msg db "You cannot execute the kernel", 13, 10, 0
binonly_msg db "You can only executre .BIN files", 13, 10, 0
press_any_key_msg db "Press any key to continue...", 13, 10, 0
kern_file_name db 'KRNLDR.SYS', 0
bin_ext db 'BIN', 0
no_file_found db "Program was not found", 13, 10, 0
os_init_msg db "Welcome to ",OS_NAME, 0
os_version_msg db "Version ", OS_VER, 0
os_msg db OS_NAME, 0
test_str db "Does show up?", 13, 10, 0
win_msg dw 0
win_msg_none db "No Menu Command", 0
win_msg_apps db "Menu Apps", 0
win_msg_term db "Menu Term", 0
win_msg_shutdown db "Menu Shutdown", 0
var_win_id db 0 ; Window type ID
var_app_index dw 0 ; App list index
buffer times 64 db 0
; ---------------------------------------------------------------
; FEATURES -- Code to pull into the kernel
%INCLUDE "features/cli.asm"
%INCLUDE "features/disk.asm"
%INCLUDE "features/keyboard.asm"
%INCLUDE "features/math.asm"
%INCLUDE "features/misc.asm"
%INCLUDE "features/screen.asm"
%INCLUDE "features/string.asm"
; ===============================================================
; END OF KERNEL
; ===============================================================
screen.asm:
Code: Select all
; ---------------------------------------------------------------
; os_print_string -- Displays text
; IN: SI = message location (zero-terminated string)
; OUT: Nothing (registers preserved)
os_print_string:
pusha
mov ah, 0Eh ; int 10h teletype function
.repeat:
lodsb ; Get char from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat ; And move on to the next char
.done:
popa
ret
; ---------------------------------------------------------------
; os_clear_screen -- Clears the screen to background
; IN/OUT: Nothing (registers preserved)
os_clear_screen:
pusha
mov dx, 0 ; Position cursor at top-left
call os_move_cursor
mov ah, 6 ; Scroll full-screen
mov al, 0 ; Normal white on black
mov bh, 7 ;
mov cx, 0 ; Top-left
mov dh, 24 ; Bottom-right
mov dl, 79
int 10h
popa
ret
; ---------------------------------------------------------------
; os_move_cursor -- Moves cursor in text mode
; IN: DH, DL = row, column; OUT: Nothing (registers preserved)
os_move_cursor:
pusha
mov bh, 0
mov ah, 2
int 10h ; BIOS interrupt to move cursor
popa
ret
; ---------------------------------------------------------------
; os_get_cursor_pos -- Return position of text cursor
; OUT: DH, DL = row, column
os_get_cursor_pos:
pusha
mov bh, 0
mov ah, 3
int 10h ; BIOS interrupt to get cursor position
mov [.tmp], dx
popa
mov dx, [.tmp]
ret
.tmp dw 0
; ---------------------------------------------------------------
; os_show_cursor -- Turns on cursor in text mode
; IN/OUT: Nothing
os_show_cursor:
pusha
mov ch, 6
mov cl, 7
mov ah, 1
mov al, 3
int 10h
popa
ret
; ---------------------------------------------------------------
; os_hide_cursor -- Turns off cursor in text mode
; IN/OUT: Nothing
os_hide_cursor:
pusha
mov ch, 32
mov ah, 1
mov al, 3 ; Must be video mode for buggy BIOSes!
int 10h
popa
ret
; ---------------------------------------------------------------
; os_print_newline -- Reset cursor to start of next line
; IN/OUT: Nothing (registers preserved)
os_print_newline:
pusha
mov ah, 0Eh ; BIOS output char code
mov al, 13
int 10h
mov al, 10
int 10h
popa
ret
; ---------------------------------------------------------------
; os_draw_horiz_line -- Draw a horizontal line on the screen
; IN: AX = line type (1 for double (-), otherwise single (=))
; OUT: Nothing (registers preserved)
os_print_horiz_line:
pusha
mov cx, ax ; Store line type param
mov al, 196 ; Default is single-line code
cmp cx, 1 ; Was double-line specified in AX?
jne .ready
mov al, 205 ; If so, here's the code
.ready:
mov cx, 0 ; Counter
mov ah, 0Eh ; BIOS output char routine
.restart:
int 10h
inc cx
cmp cx, 80 ; Drawn 80 chars yet?
je .done
jmp .restart
.done:
popa
ret
; ---------------------------------------------------------------
; os_draw_block == render block of specified color
; IN: BL/DL/DH/SI/DI = color/start X pos/start Y pos/width/finish Y pos
os_draw_block:
pusha
.more:
call os_move_cursor ; Move to block starting position
mov ah, 09h ; Draw color sections
mov bh, 0
mov cx, si
mov al, ' '
int 10h
mov ax, 0
mov al, dh ; Get current Y position into DL
cmp ax, di ; Reached finishing point (DI)?
jne .more_inc ; If not, keep drawing
popa
ret
.more_inc:
inc dh ; Get ready for next line
jmp .more
; ---------------------------------------------------------------
; os_draw_background -- Draws the default background of KirdOS
; IN: Nothing; OUT: AX = String containing current time
os_draw_background:
pusha
call os_clear_screen
; Draw default frame
mov bl, 80h
mov dl, 0
mov dh, 1
mov si, 80
mov di, 1
call os_draw_block
mov bl, 70h
mov dl, 0
mov dh, 0
mov si, 80
mov di, 0
call os_draw_block
mov bl, 70h
mov dl, 0
mov dh, 2
mov si, 80
mov di, 24
call os_draw_block
; Draw OS and Version
mov dh, 0
mov dl, 0
call os_move_cursor
mov bl, 2Fh
mov si, os_msg
call os_print_string
mov ax, os_version_msg
call os_string_length
mov dx, 79
sub dx, ax
call os_move_cursor
mov bl, 2Fh
mov si, os_version_msg
call os_print_string
; Draw Clock
mov bx, .time
call os_get_time_string
mov ax, bx
call os_string_length
mov dx, 79
sub dx, ax
mov dh, 1
call os_move_cursor
mov si, .time
mov bl, 70h
call os_print_string
popa
mov ax, .time
ret
.time times 10 db 0
; ---------------------------------------------------------------
; os_draw_menu -- Draws a menu for KirdOS
; IN/OUT: Nothing
os_draw_menu:
pusha
mov dh, 1
mov dl, 0
call os_move_cursor
mov bl, 80h
mov si, .menu_1
call os_print_string
mov si, .space
call os_print_string
mov si, .menu_2
call os_print_string
mov si, .space
call os_print_string
mov si, .menu_3
call os_print_string
popa
ret
.menu_1 db "1.APPS", 0
.menu_2 db "2.TERM", 0
.menu_3 db "3.SHUTDOWN", 0
.space db ' ', 0
; ---------------------------------------------------------------
; os_draw_windows -- Draws the windows for KirdOS
; IN: SI = Message; OUT: Nothing
os_draw_windows:
pusha
; Draw welcome
mov dl, 80
mov ax, .welcome_msg
call os_string_length
sub dl, al
mov cl, dl
.loop1:
cmp cl, 1
jle .loop1end
dec dl
sub cl, 2
jmp .loop1
.loop1end:
mov dh, 4
call os_move_cursor
mov bl, 70h
mov si, .welcome_msg
call os_print_string
mov dl, 80
mov ax, .welcome_msg_by
call os_string_length
sub dl, al
mov cl, dl
.loop2:
cmp cl, 1
jle .loop2end
dec dl
sub cl, 2
jmp .loop2
.loop2end:
mov dh, 5
call os_move_cursor
mov bl, 70h
mov si, .welcome_msg_by
call os_print_string
call os_print_newline
; Draw Debug
; Draw current windows
push ax
mov al, byte[var_win_id]
cmp al, 0
je .cont_end
cmp al, 1
je .window_apps
cmp al, 3
je .window_shutdown
.cont_end:
pop ax
popa
ret
.window_apps:
mov dl, 40
sub dl, 12
mov dh, 3
mov bl, 80h
mov si, 24
mov di, 22
call os_draw_block
add dl, 2
add dh, 2
sub si, 4
sub di, 3
mov bl, 70h
call os_draw_block
mov dl, 40
sub dl, 6
mov dh, 3
call os_move_cursor
mov bl, 80h
mov si, .select_app
call os_print_string
; Draw Debug
mov dl, 0
mov dh, 3
call os_move_cursor
mov ax, word [var_app_index]
; call os_int_to_string
mov bl, 70h
mov si, ax
; call os_print_string
.setup_applist:
call os_get_file_list
push cx
push ax
mov si, ax
mov cl, 4
jmp .newline
.more:
lodsb
cmp al, 20h
jl .donelist
cmp al, ','
je .newline
mov ah, 0Eh
int 10h
jmp .more
.newline:
add cl, 1
mov dl, 31
mov dh, cl
call os_move_cursor
jmp .more
.donelist:
pop ax
pop cx
pusha
mov ax, word [var_app_index]
mov dl, 30
mov dh, al
add dh, 5
call os_move_cursor
mov ah, 0Eh
mov al, '>'
int 10h
popa
jmp .cont_end
.window_shutdown:
jmp .cont_end
.welcome_msg db "Welcome to ",OS_NAME, 0
.welcome_msg_by db "Written by Kirdow in Assembly", 0
.select_app db "Select File ", 0
.ptr dw 0 ; Pointer to string location
.ptr_c dw 0 ; Skipped values count
.line db 0
.eof db 0
.buffer times 1024 db 0
.file_buffer times 13 db 0
.file_row db 0
; ---------------------------------------------------------------
; os_draw_screen -- Main renderer for KirdOS
; IN: Nothing; OUT: AX = String containing current time
os_draw_screen:
pusha
call os_draw_background
call os_draw_menu
call os_draw_windows
mov dh, 24
mov dl, 0
call os_move_cursor
mov word [.time], ax
popa
mov ax, word [.time]
ret
.time dw 0
; ---------------------------------------------------------------
; os_list_dialog -- Shows a list dialog to the user
; IN: AX = Question string, SI = Comma separated string of values
; OUT: AX = String containing value
os_list_dialog:
ret
helowrld.asm:
Code: Select all
; ---------------------------------------------------------------
; Hello World program
BITS 16
%INCLUDE "kirdosdev.inc"
ORG 32768
; ---------------------------------------------------------------
; Start
start:
mov si, hellow_str
call os_print_string
call os_wait_for_key
mov si, enter_name
call os_print_string
mov si, buffer
call os_get_line
mov BYTE [si], 0
push si
mov si, hello_name
call os_print_string
pop si
mov si, buffer
call os_print_string
call os_print_newline
mov si, exit_string
call os_print_string
call os_wait_for_key
ret
; ---------------------------------------------------------------
; Variables
hellow_str db "Hello World and welcome to first program", 13, 10, 0
exit_string db "Press any key to exit Hello World...", 13, 10, 0
enter_name db "What's your name? ", 0
hello_name db "Hello, ", 0
buffer times 64 db 0
; ---------------------------------------------------------------
; main
these positions refer to the os_call_vectors in the top of kernel.asm
kirdosdev.inc:
Code: Select all
; ---------------------------------------------------------------
; Include file for KirdOS program development
; ---------------------------------------------------------------
; ---------------------------------------------------------------
; IMPARTANT LOCATIONS
os_main equ 0000h ; Where the OS code starts
; ---------------------------------------------------------------
; KEYS
%DEFINE KEY_UP 72
%DEFINE KEY_DOWN 80
%DEFINE KEY_LEFT 75
%DEFINE KEY_RIGHT 77
%DEFINE KEY_ESC 27
%DEFINE KEY_ENTER 13
; ---------------------------------------------------------------
; SYSTEM CALLS
; Screen control
os_print_string equ 0003h ; SI = zero-terminated string location
os_clear_screen equ 0006h ; (Nothing used)
os_move_cursor equ 0009h ; DH, DL = row, column
os_get_cursor_pos equ 000Ch ; OUT: DH = row, DL = column
os_show_cursor equ 000Fh ; (Nothing used)
os_hide_cursor equ 0012h ; (Nothing used)
os_print_newline equ 0015h ; (Nothing used)
; Keyboard control
os_wait_for_key equ 0036h ; Returns AL = key pressed
os_check_for_key equ 0039h ; Returns AL = key pressed
os_get_line equ 003Ch ; IN/OUT: SI = 64 byte buffer input
; String control
os_string_length equ 001Bh ; AX = string loc, returns AL = length
os_string_reverse equ 001Eh ; SI = string location
os_string_uppercase equ 0021h ; AX = zero-terminated string
os_string_lowercase equ 0024h ; AX = zero-terminated string
os_string_compare equ 0027h ; SI, DI = strings, carry set if same
; Math control
os_get_random equ 002Dh ; IN: AX, BX = low, high; OUT: CX = num
; Misc OS functions
os_pause equ 0030h ; AX = 10ths of second to wait
os_fatal_error equ 0033h ; AX = error string location
So to describe my problem and what I've found when trying to fix it.
So my bootloader is fine, that one just loads the kernel as a file on the FAT12 Floppy. It then loads it to ram
position 2000h and jumps to that position using jmp 2000h:0000h
Then in the start of the kernel it sets up the required segments.
in the main_loop function it first clears the screen with a function in screen.asm which is further up in this post.
after that it draws the screen.
then it jumps to a subfunction (.label) which freeze the os for 0.55 seconds and then continues where it was.
It then waits for the user to press a key, and also checks if the key pressed is greater than zero, if it is, it handles the inputted key. If it is zero though, it just waits for a new key to be pressed.
then it checks the value of var_win_id, which is a variable telling which window is currently open. If the apps window is open, it jumps to .ck_apps (which is short for .check_keys_apps) and checks the input there. If the value is 3, it jumps to the .ck_shutdown label which currently just goes back to the main loop instead of shutting down. If there is no window open, it just checks if the user pressed any of the keys 1 - 3 which is command. For example if user press the '1' key, it sets var_win_id to 1, which would again run .ck_apps if a key is pressed.
We're gonna take a look in .ck_apps.
.ck_apps has 3 (or 4, but the last 2 just checks the same key but 2 different versions) keys which it checks. UP, DOWN and ENTER/RETURN. Up and Down just cycle thru the files to choose from the Floppy, listed in a list box. If the user press ENTER though, it jumps to .ckapps_enter, which copies the filename selected into a variable. Note that alot of the following uses subfunctions, which has a . in front of the label. I wouldn't recommend doing this though, but I had to do it I remember for a thing to work, so I will keep it like that for now. but anyawy after the filename is copied, it continues in .ckapps_load, which first checks if the file exists. I haven't posted any of the diskmanagement code as I know they work correctly. if the file contains, it then checks if the filename is KRNLDR.SYS, which would be the kernel, and if it is, it would prompt the user it can't run the kernel, and then go back to redrawing the os and wait for a key. But if the file selected isn't the kernel, it then checks if the extension is .bin, which is the currently only extension which can get executed. if the file is a .bin file, it then loads the file to 32768 (or 0x8000). This is confirmed too that it loads the file to ram. after it has loaded the file, it jumps to .execute_bin_extension, which clears the screen, resets the registers ax, bx, cx, dx, si and di to 0. then runs "call 32768" to call the program code. after the program is done, it clears the screen and goes back to the beginning of main_loop.
So, in the program code (helowrld.asm), it firsts moves hellow_str to si, which is a pointer to a string declared in the bottom of the program code. After that it run os_print_string, which is defined in kirdosdev.inc as "os_print_string equ 0003h". What happens next is that the os just freeze, and nothing more happens. This is where I though the program wasn't actually loaded. So I tried comparing values in the program (using the position in ram where the program is, and declaring values in the program code with "db <byte>"), both from the kernel, and program, and logging them to the user (when I log it to the user from the program, I just copied the code from the kernel into the program code), which actually both gave the correct result. Which means the program actually loads and gets executed. Then I try something else, I check the call vectors to see if they are different depending on if the kernel or the program is running. But they were still the same.
I then tried to jump to the call vectors from within the kernel. And what do I find, I find that the code actually freezes. I wrote "call os_print_string" on a value, which then print the value I entered in si register. I then wrote "call 0003h", which refers to some code saying "jmp os_print_string", and this time it doesn't print the value, instead it freezes again. So appearently, I suppose, there's some problem with the call vectors. I then tried putting a label before the "jmp os_print_string" code and calling that one. Same thing there, it freezes.
I then tried decompiling, and found that the call vector for 0003h say "jmp word 0x16d8". So I went to byte number 0x16d8, and checked the code to see if it were something else than the os_print_string function. What do I find out? I found out that it is the os_print_string function, which is what it should be. This is where my ideas stop. I've tried what I could, I've compared the code with the code from MikeOS, and all the critical parts are the same. So now I have no clue anymore how to fix this.