├── LICENSE.md ├── README.md ├── bochsrc ├── bootloader ├── bootloader.asm └── functions │ ├── a20_enabler.inc │ ├── disk.inc │ ├── enter_unreal.inc │ ├── gdt.inc │ └── simple_print.inc ├── extra └── fun │ └── dank.pic ├── includes ├── music.inc └── shell │ ├── cat.inc │ ├── cd.inc │ ├── clear.inc │ ├── colour.inc │ ├── debug.inc │ ├── exit.inc │ ├── help.inc │ ├── image.inc │ ├── ls.inc │ ├── root.inc │ ├── time.inc │ └── ver.inc ├── kernel ├── external │ ├── allocate_mem32.inc │ ├── allocate_memory.inc │ ├── ascii_dump.inc │ ├── beep.inc │ ├── center_print_string.inc │ ├── clear_frame_buffer.inc │ ├── compare_strings.inc │ ├── cut_string.inc │ ├── directory_scanner.inc │ ├── disable_cursor.inc │ ├── draw_line.inc │ ├── draw_pixel.inc │ ├── draw_sprite.inc │ ├── enable_cursor.inc │ ├── enter_graphics_mode.inc │ ├── exit_graphics_mode.inc │ ├── fat_time_to_integer.inc │ ├── floppy_read_byte.inc │ ├── floppy_read_dword.inc │ ├── floppy_read_sectors.inc │ ├── floppy_read_word.inc │ ├── floppy_write_byte.inc │ ├── floppy_write_dword.inc │ ├── floppy_write_sectors.inc │ ├── floppy_write_word.inc │ ├── get_char.inc │ ├── get_current_dir.inc │ ├── get_current_drive.inc │ ├── get_current_palette.inc │ ├── get_cursor_position.inc │ ├── get_version_number.inc │ ├── initialise_screen.inc │ ├── input_integer.inc │ ├── input_string.inc │ ├── invalid_cache.inc │ ├── load_dir.inc │ ├── load_file.inc │ ├── lower_to_uppercase.inc │ ├── new_line.inc │ ├── pause.inc │ ├── ping_file.inc │ ├── play_music.inc │ ├── print_integer.inc │ ├── print_integer_hex.inc │ ├── print_string.inc │ ├── push_frame.inc │ ├── put_char.inc │ ├── set_current_drive.inc │ ├── set_cursor_position.inc │ ├── set_palette.inc │ ├── sleep.inc │ ├── start_new_program.inc │ ├── stop_beep.inc │ ├── stop_music.inc │ ├── string_copy.inc │ ├── string_end.inc │ ├── string_length.inc │ ├── string_to_integer.inc │ ├── terminate_process.inc │ ├── timer_read.inc │ └── upper_to_lowercase.inc ├── internal │ ├── check_bin_extension.inc │ ├── clear_cursor.inc │ ├── draw_cursor.inc │ ├── erase_dir_cache.inc │ ├── fat12_delete_chain.inc │ ├── fat12_load_chain.inc │ ├── fat_delete_chain.inc │ ├── fat_get_metadata.inc │ ├── fat_load_chain.inc │ ├── fat_load_root.inc │ ├── fat_name_to_string.inc │ ├── fat_write_entry.inc │ ├── fat_write_root.inc │ ├── floppy_read_sector.inc │ ├── floppy_write_sector.inc │ ├── path_converter.inc │ └── string_to_fat_name.inc ├── kernel.asm └── other │ ├── break_int.inc │ ├── syscalls.inc │ ├── timer_int.inc │ └── variables.inc ├── make_me.sh └── sources ├── beep.asm └── shell.asm /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017, The people that worked on DankOS 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DankOS 2 | A really simple Real Mode OS, in honour of youtuber Druaga1. 3 | 4 | # Building requirements 5 | Currently, there is no Windows make script, so this only builds on GNU/Linux 6 | and FreeBSD systems. 7 | 8 | In order to successfully build the OS, these packages should be installed: 9 | 10 | - bash (to run the make_me script) 11 | - nasm 12 | 13 | # Building instructions 14 | The 'make_me.sh' bash script automatically builds the image, and assembles all 15 | the sources from the 'sources' directory. 16 | 17 | All files/dirs from the 'extra' directory will also be copied onto the image. 18 | 19 | -------------------------------------------------------------------------------- /bochsrc: -------------------------------------------------------------------------------- 1 | megs: 256 2 | 3 | clock: sync=realtime, time0=local 4 | 5 | floppya: 1_44=./dankos.img, status=inserted 6 | 7 | boot: floppy 8 | 9 | log: ./bochsout.txt 10 | 11 | mouse: enabled=0 12 | 13 | magic_break: enabled=1 14 | -------------------------------------------------------------------------------- /bootloader/bootloader.asm: -------------------------------------------------------------------------------- 1 | ; ************************* 2 | ; DankOS BOOTLOADER 3 | ; ************************* 4 | 5 | org 0x7C00 ; BIOS loads us here (0000:7C00) 6 | bits 16 ; 16-bit real mode code 7 | 8 | jmp short code_start ; Jump to the start of the code 9 | nop ; Pad with NOP instruction 10 | times 3-($-$$) db 0x00 ; Make sure this is the start of the BPB 11 | 12 | ; The BPB starts here 13 | 14 | bpbOEM db 'DANK OS ' 15 | bpbBytesPerSector dw 512 16 | bpbSectorsPerCluster db 1 17 | bpbReservedSectors dw 68 18 | bpbNumberOfFATs db 2 19 | bpbRootEntries dw 224 20 | bpbTotalSectors dw 2880 21 | bpbMedia db 0xF8 22 | bpbSectorsPerFAT dw 9 23 | bpbSectorsPerTrack dw 18 24 | bpbHeadsPerCylinder dw 2 25 | bpbHiddenSectors dd 0 26 | bpbTotalSectorsBig dd 0 27 | bsDriveNumber db 0x00 28 | bsUnused db 0x00 29 | bsExtBootSignature db 0x29 30 | bsSerialNumber dd 0x12345678 31 | bsVolumeLabel db 'DANK OS ' 32 | bsFileSystem db 'FAT12 ' 33 | 34 | ; End of BPB, start of main bootloader code 35 | 36 | code_start: 37 | 38 | cli 39 | jmp 0x0000:initialise_cs ; Initialise CS to 0x0000 with a long jump 40 | initialise_cs: 41 | xor ax, ax 42 | mov ds, ax 43 | mov es, ax 44 | mov fs, ax 45 | mov gs, ax 46 | mov ax, 0x1000 47 | mov ss, ax 48 | mov sp, 0xFFF0 49 | sti 50 | 51 | mov si, LoadingMsg ; Print loading message using simple print (BIOS) 52 | call simple_print 53 | 54 | ; ****************** Load stage 2 ****************** 55 | 56 | mov si, Stage2Msg ; Print loading stage 2 message 57 | call simple_print 58 | 59 | mov ax, 1 ; Start from LBA sector 1 60 | mov bx, 0x7E00 ; Load to offset 0x7E00 61 | mov cx, 3 ; Load 3 sectors 62 | call read_sectors 63 | 64 | jc err ; Catch any error 65 | 66 | mov si, DoneMsg 67 | call simple_print ; Display done message 68 | 69 | jmp stage2 ; Jump to stage 2 70 | 71 | err: 72 | mov si, ErrMsg 73 | call simple_print 74 | 75 | halt: 76 | hlt 77 | jmp halt 78 | 79 | ;Data 80 | 81 | LoadingMsg db 0x0D, 0x0A, 'Loading DankOS...', 0x0D, 0x0A, 0x0A, 0x00 82 | Stage2Msg db 'Loading Stage 2...', 0x00 83 | A20Msg db 'Enabling A20 line...', 0x00 84 | UnrealMsg db 'Enabling Unreal Mode...', 0x00 85 | KernelMsg db 'Loading kernel...', 0x00 86 | ErrMsg db 0x0D, 0x0A, 'Error, system halted.', 0x00 87 | DoneMsg db ' DONE', 0x0D, 0x0A, 0x00 88 | 89 | ;Includes 90 | 91 | %include 'bootloader/functions/simple_print.inc' 92 | %include 'bootloader/functions/disk.inc' 93 | 94 | times 510-($-$$) db 0x00 ; Fill rest with 0x00 95 | bios_signature dw 0xAA55 ; BIOS signature 96 | 97 | 98 | stage2: 99 | 100 | ; ************************* STAGE 2 ************************ 101 | 102 | ; ***** A20 ***** 103 | 104 | mov si, A20Msg ; Display A20 message 105 | call simple_print 106 | 107 | call enable_a20 ; Enable the A20 address line to access high memory 108 | jc err ; If it fails, print an error and halt 109 | 110 | mov si, DoneMsg 111 | call simple_print ; Display done message 112 | 113 | ; ***** Unreal Mode ***** 114 | 115 | mov si, UnrealMsg ; Display unreal message 116 | call simple_print 117 | 118 | %include 'bootloader/functions/enter_unreal.inc' ; Enter Unreal Mode 119 | 120 | mov si, DoneMsg 121 | call simple_print ; Display done message 122 | 123 | ; ***** Kernel ***** 124 | 125 | mov si, KernelMsg ; Show loading kernel message 126 | call simple_print 127 | 128 | ; Load the kernel to a buffer first, to avoid bugs with BIOS's int 0x13 failing to load into HMA 129 | 130 | mov ax, 0x2000 131 | mov es, ax 132 | mov ax, 4 ; Start from LBA sector 4 133 | mov bx, 0x0010 ; Load to offset 0x0010 134 | mov cx, 64 ; Load 64 sectors (32 KB) 135 | call read_sectors 136 | 137 | jc err ; Catch any error 138 | 139 | mov si, DoneMsg 140 | call simple_print ; Display done message 141 | 142 | ; Then move kernel to HMA 143 | 144 | mov ax, es 145 | mov ds, ax 146 | xor ax, ax 147 | not ax 148 | mov es, ax 149 | 150 | xor si, si 151 | xor di, di 152 | 153 | xor cx, cx 154 | not cx 155 | 156 | rep movsb 157 | 158 | ; Done! 159 | 160 | jmp 0xFFFF:0x0010 ; Jump to the newly loaded kernel 161 | 162 | 163 | ; Stage 2 includes 164 | 165 | %include 'bootloader/functions/a20_enabler.inc' 166 | %include 'bootloader/functions/gdt.inc' 167 | 168 | times 2048-($-$$) db 0x00 ; Padding 169 | -------------------------------------------------------------------------------- /bootloader/functions/a20_enabler.inc: -------------------------------------------------------------------------------- 1 | a20_check: 2 | 3 | ; ************************************************* 4 | ; Checks if the A20 address line is enabled 5 | ; ************************************************* 6 | 7 | ; OUT: 8 | ; Carry if disabled, cleared if enabled 9 | 10 | push ax ; Save registers 11 | push bx 12 | push es 13 | push fs 14 | 15 | xor ax, ax ; Set ES segment to zero 16 | mov es, ax 17 | not ax ; Set FS segment to 0xFFFF 18 | mov fs, ax 19 | 20 | mov ax, word [es:0x7DFE] ; Check using boot signature 21 | cmp word [fs:0x7E0E], ax ; If A20 is disabled, this should be the 22 | ; same address as the boot signature 23 | je .change_values ; If they are equal, check again with another value 24 | 25 | .enabled: 26 | 27 | clc ; A20 is enabled, clear carry flag 28 | jmp .done 29 | 30 | .change_values: 31 | 32 | mov word [es:0x7DFE], 0x1234 ; Change the value of 0000:7DFE to 0x1234 33 | cmp word [fs:0x7E0E], 0x1234 ; Is FFFF:7E0E changed as well? 34 | jne .enabled ; If it is, A20 is enabled 35 | 36 | stc ; Otherwise set carry 37 | 38 | .done: 39 | 40 | mov word [es:0x7DFE], ax ; Restore boot signature 41 | pop fs ; Restore registers 42 | pop es 43 | pop bx 44 | pop ax 45 | ret ; Exit routine 46 | 47 | 48 | 49 | 50 | enable_a20: 51 | 52 | ; ******************************************** 53 | ; Tries to enable the A20 address line 54 | ; ******************************************** 55 | 56 | ; OUT: 57 | ; Carry cleared if success, set if fail 58 | 59 | push eax ; Save registers 60 | 61 | call a20_check ; Check if a20 is already enabled 62 | jnc .done ; If it is, we are done 63 | 64 | mov ax, 0x2401 ; Use BIOS to try to enable a20 65 | int 0x15 66 | 67 | call a20_check ; Check again to see if BIOS succeeded 68 | jnc .done ; If it has, we are done 69 | 70 | .keyboard_method: 71 | 72 | cli ; Disable interrupts 73 | 74 | call .a20wait ; Use the keyboard controller to try and 75 | mov al, 0xAD ; open the A20 gate 76 | out 0x64, al 77 | 78 | call .a20wait 79 | mov al, 0xD0 80 | out 0x64, al 81 | 82 | call .a20wait2 83 | in al, 0x60 84 | push eax 85 | 86 | call .a20wait 87 | mov al, 0xD1 88 | out 0x64, al 89 | 90 | call .a20wait 91 | pop eax 92 | or al, 2 93 | out 0x60, al 94 | 95 | call .a20wait 96 | mov al, 0xAE 97 | out 0x64, al 98 | 99 | call .a20wait 100 | sti ; Enable interrupts back 101 | 102 | jmp .keyboard_done 103 | 104 | .a20wait: 105 | 106 | in al, 0x64 107 | test al, 2 108 | jnz .a20wait 109 | ret 110 | 111 | .a20wait2: 112 | 113 | in al, 0x64 114 | test al, 1 115 | jz .a20wait2 116 | ret 117 | 118 | .keyboard_done: 119 | 120 | call a20_check ; Check for success 121 | 122 | ; Now just quit the routine, forwarding the carry flag to the caller 123 | 124 | .done: 125 | pop eax 126 | ret 127 | -------------------------------------------------------------------------------- /bootloader/functions/disk.inc: -------------------------------------------------------------------------------- 1 | read_sector: 2 | 3 | ; ************************************************* 4 | ; Reads a floppy sector with an LBA address 5 | ; ************************************************* 6 | 7 | ; IN: 8 | ; AX = LBA sector to load 9 | ; DL = Drive number 10 | ; ES = Buffer segment 11 | ; BX = Buffer offset 12 | 13 | ; OUT: 14 | ; Carry if error 15 | 16 | push ax ; Save all GPRs 17 | push bx ; Prepare entering routine 18 | push cx 19 | push dx 20 | 21 | push dx ; Save drive number in stack 22 | 23 | ; LBA to CHS 24 | 25 | xor dx, dx ; XOR DX for division 26 | div word [bpbSectorsPerTrack] ; Divide LBA / Sectors per track 27 | inc dl ; Adjust for sector 0 28 | mov byte [.absolute_sector], dl ; Save sector 29 | xor dx, dx ; XOR DX for division 30 | div word [bpbHeadsPerCylinder] ; Divide / Number of heads 31 | mov byte [.absolute_head], dl ; Save head 32 | mov byte [.absolute_track], al ; Save track 33 | 34 | pop dx ; Restore drive number from stack 35 | 36 | ; Prepare registers for BIOS int 0x13 37 | 38 | mov ah, 0x02 ; Read sector function 39 | mov al, 1 ; Read 1 sector 40 | mov ch, byte [.absolute_track] ; Use data we calculated 41 | mov cl, byte [.absolute_sector] 42 | mov dh, byte [.absolute_head] 43 | 44 | clc ; Clear carry for int 0x13 because some BIOSes may not clear it on success 45 | 46 | int 0x13 ; Call int 0x13 47 | 48 | .done: 49 | 50 | pop dx ; Restore all GPRs 51 | pop cx 52 | pop bx 53 | pop ax 54 | ret ; Exit routine 55 | 56 | 57 | .absolute_sector db 0x00 58 | .absolute_head db 0x00 59 | .absolute_track db 0x00 60 | 61 | 62 | read_sectors: 63 | 64 | ; ********************************************************** 65 | ; Reads multiple LBA addressed sectors from a floppy 66 | ; ********************************************************** 67 | 68 | ; IN: 69 | ; AX = LBA starting sector 70 | ; DL = Drive number 71 | ; ES = Buffer segment 72 | ; BX = Buffer offset 73 | ; CX = Sectors count 74 | 75 | ; OUT: 76 | ; Carry if error 77 | 78 | push ax ; Save GPRs 79 | push bx 80 | push cx 81 | 82 | .loop: 83 | 84 | call read_sector ; Read sector 85 | jc .done ; If carry exit with flag 86 | 87 | inc ax ; Increment sector 88 | add bx, 512 ; Add 512 to the buffer 89 | 90 | loop .loop ; Loop! 91 | 92 | .done: 93 | pop cx ; Restore GPRs 94 | pop bx 95 | pop ax 96 | ret ; Exit routine 97 | -------------------------------------------------------------------------------- /bootloader/functions/enter_unreal.inc: -------------------------------------------------------------------------------- 1 | enter_unreal: 2 | 3 | cli ; Disable interrupts 4 | 5 | lgdt [GDT] ; Load the GDT 6 | 7 | mov eax, cr0 ; Enable bit 0 of cr0 and enter protected mode 8 | or eax, 00000001b 9 | mov cr0, eax 10 | 11 | jmp 0x08:.pmode 12 | 13 | .pmode: ; Now in protected mode 14 | 15 | mov ax, 0x10 16 | mov ds, ax 17 | mov es, ax 18 | mov fs, ax 19 | mov gs, ax 20 | mov ss, ax 21 | 22 | mov eax, cr0 ; Exit protected mode 23 | and eax, 11111110b 24 | mov cr0, eax 25 | 26 | jmp 0x0000:.unreal_mode 27 | 28 | .unreal_mode: ; Now in Unreal Mode 29 | 30 | xor ax, ax 31 | mov ds, ax 32 | mov es, ax 33 | mov fs, ax 34 | mov gs, ax 35 | mov ax, 0x1000 36 | mov ss, ax 37 | mov sp, 0xFFF0 38 | 39 | sti ; Enable interrupts 40 | -------------------------------------------------------------------------------- /bootloader/functions/gdt.inc: -------------------------------------------------------------------------------- 1 | GDT: 2 | 3 | dw .GDTEnd - .GDTStart - 1 ; GDT size 4 | dd .GDTStart ; GDT start 5 | 6 | .GDTStart: 7 | 8 | ; Null descriptor (required) 9 | 10 | .NullDescriptor: 11 | 12 | dw 0x0000 ; Limit 13 | dw 0x0000 ; Base (low 16 bits) 14 | db 0x00 ; Base (mid 8 bits) 15 | db 00000000b ; Access 16 | db 00000000b ; Granularity 17 | db 0x00 ; Base (high 8 bits) 18 | 19 | ; Unreal mode 20 | 21 | .UnrealCode: 22 | 23 | dw 0xFFFF ; Limit 24 | dw 0x0000 ; Base (low 16 bits) 25 | db 0x00 ; Base (mid 8 bits) 26 | db 10011010b ; Access 27 | db 10001111b ; Granularity 28 | db 0x00 ; Base (high 8 bits) 29 | 30 | .UnrealData: 31 | 32 | dw 0xFFFF ; Limit 33 | dw 0x0000 ; Base (low 16 bits) 34 | db 0x00 ; Base (mid 8 bits) 35 | db 10010010b ; Access 36 | db 10001111b ; Granularity 37 | db 0x00 ; Base (high 8 bits) 38 | 39 | .GDTEnd: 40 | -------------------------------------------------------------------------------- /bootloader/functions/simple_print.inc: -------------------------------------------------------------------------------- 1 | simple_print: 2 | 3 | ; ************************************** 4 | ; Prints a string using the BIOS 5 | ; ************************************** 6 | 7 | ; IN: 8 | ; SI = points to a 0x00 terminated string 9 | 10 | push ax ; Save registers 11 | push si 12 | mov ah, 0x0E ; int 0x10, function 0x0E (print character) 13 | .loop: 14 | lodsb ; Load character from string 15 | test al, al ; Is is the 0x00 terminator? 16 | jz .done ; If it is, exit routine 17 | int 0x10 ; Call BIOS 18 | jmp .loop ; Repeat! 19 | .done: 20 | pop si ; Restore registers 21 | pop ax 22 | ret ; Exit routine 23 | -------------------------------------------------------------------------------- /extra/fun/dank.pic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Druaga1/DankOS/410994a7106bd079e81eaec7d50f39e314bd2bfa/extra/fun/dank.pic -------------------------------------------------------------------------------- /includes/music.inc: -------------------------------------------------------------------------------- 1 | ; Defines the music note's frequencies 2 | 3 | A_oct_below equ 220 4 | A_sharp_oct_below equ 233 5 | B_oct_below equ 247 6 | C_oct_below equ 262 7 | C_sharp_oct_below equ 277 8 | D_oct_below equ 294 9 | D_sharp_oct_below equ 311 10 | E_oct_below equ 330 11 | F_oct_below equ 349 12 | F_sharp_oct_below equ 370 13 | G_oct_below equ 392 14 | G_sharp_oct_below equ 415 15 | A equ 440 16 | A_sharp equ 466 17 | B equ 494 18 | C equ 523 19 | C_sharp equ 554 20 | D equ 587 21 | D_sharp equ 622 22 | E equ 659 23 | F equ 698 24 | F_sharp equ 740 25 | G equ 784 26 | G_sharp equ 831 27 | A_oct_above equ 880 28 | A_sharp_oct_above equ 932 29 | B_oct_above equ 988 30 | C_oct_above equ 1047 31 | C_sharp_oct_above equ 1109 32 | D_oct_above equ 1175 33 | D_sharp_oct_above equ 1245 34 | E_oct_above equ 1319 35 | F_oct_above equ 1397 36 | F_sharp_oct_above equ 1480 37 | G_oct_above equ 1568 38 | G_sharp_oct_above equ 1661 39 | -------------------------------------------------------------------------------- /includes/shell/cat.inc: -------------------------------------------------------------------------------- 1 | ; **** cat command **** 2 | 3 | cat_cmd: 4 | 5 | mov si, command_line_switches 6 | cmp byte [si], 0x00 7 | je .missing_parameter 8 | 9 | push es ; Set up target segment:offset 10 | mov ax, word [FileBuffer] 11 | mov es, ax 12 | xor bx, bx 13 | 14 | push 0x12 ; Load file into buffer 15 | int 0x80 16 | pop es 17 | 18 | test dl, dl ; Check for failure 19 | jnz .failure 20 | 21 | push ds 22 | mov ax, word [FileBuffer] 23 | mov ds, ax 24 | 25 | xor si, si 26 | 27 | .loop: 28 | lodsb 29 | push 0x01 30 | int 0x80 31 | loop .loop 32 | 33 | pop ds 34 | 35 | jmp prompt_loop 36 | 37 | 38 | .missing_parameter: 39 | 40 | mov si, .missing_parameter_msg 41 | push 0x02 42 | int 0x80 43 | jmp prompt_loop 44 | 45 | .failure: 46 | 47 | mov si, .failure_msg 48 | push 0x02 49 | int 0x80 50 | jmp prompt_loop 51 | 52 | 53 | 54 | 55 | 56 | .missing_parameter_msg db 'Required parameter missing: file name.', 0x0A, 0x00 57 | .failure_msg db 'File not found.', 0x0A, 0x00 58 | -------------------------------------------------------------------------------- /includes/shell/cd.inc: -------------------------------------------------------------------------------- 1 | ; **** cd command **** 2 | 3 | cd_cmd: 4 | 5 | mov si, command_line_switches 6 | cmp byte [si], 0x00 7 | je .missing_parameter 8 | 9 | push 0x21 ; Load directory 10 | int 0x80 11 | 12 | test dl, dl ; Check for failure 13 | jnz .failure 14 | 15 | jmp prompt_loop 16 | 17 | 18 | .missing_parameter: 19 | 20 | mov si, .missing_parameter_msg 21 | push 0x02 22 | int 0x80 23 | jmp prompt_loop 24 | 25 | .failure: 26 | 27 | mov si, .failure_msg 28 | push 0x02 29 | int 0x80 30 | jmp prompt_loop 31 | 32 | 33 | 34 | 35 | 36 | .missing_parameter_msg db 'Required parameter missing: directory name.', 0x0A, 0x00 37 | .failure_msg db 'Directory not found.', 0x0A, 0x00 38 | -------------------------------------------------------------------------------- /includes/shell/clear.inc: -------------------------------------------------------------------------------- 1 | ; ** Clear command ** 2 | 3 | clear_cmd: 4 | 5 | push 0x0A 6 | int 0x80 ; Reinitialise screen 7 | jmp prompt_loop ; Return to prompt 8 | -------------------------------------------------------------------------------- /includes/shell/colour.inc: -------------------------------------------------------------------------------- 1 | ; **** Colour command **** 2 | 3 | colour_cmd: 4 | 5 | mov si, command_line_switches 6 | cmp byte [si], 0x00 7 | je .missing_parameter 8 | 9 | push 0x17 10 | int 0x80 11 | 12 | mov bl, al 13 | 14 | push 0x04 15 | int 0x80 16 | 17 | mov ah, al 18 | mov al, bl 19 | 20 | push 0x11 21 | int 0x80 22 | 23 | jmp prompt_loop ; Return to prompt 24 | 25 | 26 | 27 | .missing_parameter: 28 | 29 | mov si, .missing_parameter_msg 30 | push 0x02 31 | int 0x80 32 | jmp prompt_loop 33 | 34 | 35 | 36 | 37 | 38 | .missing_parameter_msg db 'Required parameter missing: palette 0-255.', 0x0A, 0x00 39 | -------------------------------------------------------------------------------- /includes/shell/debug.inc: -------------------------------------------------------------------------------- 1 | ; **** Debug command **** 2 | 3 | debug_cmd: 4 | 5 | mov ebx, 511 6 | mov eax, 0x05060708 7 | xor dl, dl 8 | 9 | push 0x34 10 | int 0x80 11 | 12 | jmp prompt_loop ; Return to prompt 13 | -------------------------------------------------------------------------------- /includes/shell/exit.inc: -------------------------------------------------------------------------------- 1 | ; **** Exit command **** 2 | 3 | exit_cmd: 4 | 5 | xor eax, eax ; Exit code = 0 6 | push 0x00 7 | int 0x80 8 | -------------------------------------------------------------------------------- /includes/shell/help.inc: -------------------------------------------------------------------------------- 1 | ; **** Help command **** 2 | 3 | help_cmd: 4 | 5 | mov si, .help_msg ; Display help message 6 | push 0x02 7 | int 0x80 8 | 9 | jmp prompt_loop ; Return to prompt 10 | 11 | 12 | .help_msg: 13 | 14 | db "DankOS shell, list of internal commands.", 0x0A 15 | db 0x0A 16 | db " clear -- Clears the screen.", 0x0A 17 | db " ls/dir -- Lists the files in the drive.", 0x0A 18 | db " cd -- Changes the present working directory.", 0x0A 19 | db " cat -- Displays the content of a file.", 0x0A 20 | db " time -- Displays the current time.", 0x0A 21 | db " image -- Displays the content of a DankOS formatted image file.", 0x0A 22 | db " colour -- Sets the text mode palette. (Use 'clear' to apply).", 0x0A 23 | db " root -- Sets a new root drive.", 0x0A 24 | db " ver -- Shows the current version of the kernel.", 0x0A 25 | db " help -- Shows this list.", 0x0A 26 | db " exit -- Closes the shell.", 0x0A 27 | db 0x00 28 | -------------------------------------------------------------------------------- /includes/shell/image.inc: -------------------------------------------------------------------------------- 1 | ; **** image command **** 2 | 3 | image_cmd: 4 | 5 | mov si, command_line_switches 6 | cmp byte [si], 0x00 7 | je .missing_parameter 8 | 9 | ; save old palette 10 | 11 | push 0x17 12 | int 0x80 13 | mov word [.old_palette], ax 14 | 15 | push es ; Set up target segment:offset 16 | mov ax, word [FileBuffer] 17 | mov es, ax 18 | xor bx, bx 19 | 20 | push 0x12 ; Load file into buffer 21 | int 0x80 22 | pop es 23 | 24 | test dl, dl ; Check for failure 25 | jnz .failure 26 | 27 | push ds 28 | mov ax, word [FileBuffer] 29 | mov ds, ax 30 | 31 | push 0x80 ; Enter graphics mode 32 | int 0x80 33 | 34 | xor si, si 35 | xor bx, bx 36 | xor cl, cl 37 | 38 | push 0x84 ; Draw sprite 39 | int 0x80 40 | 41 | push 0x86 ; Push frame 42 | int 0x80 43 | pop ds 44 | 45 | push 0x18 ; Pause 46 | int 0x80 47 | 48 | push 0x82 ; Exit graphics mode 49 | int 0x80 50 | 51 | mov ax, word [.old_palette] ; restore old palette 52 | push 0x11 53 | int 0x80 54 | 55 | push 0x0A ; Reinitialise 56 | int 0x80 57 | 58 | jmp prompt_loop 59 | 60 | .missing_parameter: 61 | 62 | mov si, .missing_parameter_msg 63 | push 0x02 64 | int 0x80 65 | jmp prompt_loop 66 | 67 | .failure: 68 | 69 | mov si, .failure_msg 70 | push 0x02 71 | int 0x80 72 | jmp prompt_loop 73 | 74 | 75 | 76 | .old_palette dw 0x0000 77 | 78 | .missing_parameter_msg db 'Required parameter missing: file name.', 0x0A, 0x00 79 | .failure_msg db 'File not found.', 0x0A, 0x00 80 | .failure_not_image_msg db 'This file is not an image.', 0x0A, 0x00 81 | -------------------------------------------------------------------------------- /includes/shell/ls.inc: -------------------------------------------------------------------------------- 1 | ; **** ls command **** 2 | 3 | ls_cmd: 4 | 5 | mov di, .FileName 6 | 7 | mov word [.EntryCounter], 0x0000 8 | mov dword [.TotalSize], 0x00000000 9 | mov word [.FilesNumber], 0x0000 10 | mov word [.DirectoriesNumber], 0x0000 11 | 12 | .loop: 13 | 14 | mov ax, word [.EntryCounter] 15 | 16 | push 0x28 17 | int 0x80 18 | 19 | test dl, dl 20 | jnz .summary ; If end of table, print summary 21 | 22 | inc word [.EntryCounter] 23 | 24 | mov dword [.Size], ecx ; Save size 25 | add dword [.TotalSize], ecx ; Increase total size 26 | mov byte [.Directory], dh 27 | 28 | cmp byte [.Directory], 0xFF ; Check if the entry is a directory 29 | jne .file_entry 30 | 31 | inc word [.DirectoriesNumber] 32 | jmp .convert_time 33 | 34 | .file_entry: 35 | inc word [.FilesNumber] 36 | 37 | .convert_time: 38 | 39 | push 0x2C ; Convert to standard time 40 | int 0x80 41 | 42 | mov byte [.Seconds], al 43 | mov byte [.Minutes], ah 44 | mov byte [.Hours], bl 45 | mov byte [.Days], bh 46 | mov byte [.Months], cl 47 | mov word [.Years], dx 48 | 49 | cmp byte [.Directory], 0xFF ; Check if the entry is a directory 50 | jne .skip_bracket1 51 | 52 | mov al, '[' 53 | push 0x01 54 | int 0x80 55 | .skip_bracket1: 56 | 57 | mov si, .FileName ; Print file name 58 | push 0x02 59 | int 0x80 60 | 61 | cmp byte [.Directory], 0xFF ; Check if the entry is a directory 62 | jne .skip_bracket2 63 | 64 | mov al, ']' 65 | push 0x01 66 | int 0x80 67 | .skip_bracket2: 68 | 69 | push 0x0D 70 | int 0x80 ; Get cursor coordinates 71 | 72 | mov ah, 15 ; Set the X to 15 73 | 74 | push 0x0E 75 | int 0x80 ; Set cursor coordinates 76 | 77 | cmp byte [.Directory], 0xFF ; Check if the entry is a directory 78 | je .skip_size 79 | 80 | xor cl, cl 81 | mov eax, dword [.Size] ; Print size, right align 82 | mov dl, 0x01 83 | push 0x06 84 | int 0x80 85 | 86 | mov si, .bytes_msg ; Print bytes 87 | push 0x02 88 | int 0x80 89 | .skip_size: 90 | 91 | push 0x0D 92 | int 0x80 ; Get cursor coordinates 93 | 94 | mov ah, 35 ; X = 35 95 | 96 | push 0x0E 97 | int 0x80 ; Set cursor coordinates 98 | 99 | xor dl, dl ; Left align 100 | 101 | mov cl, 2 102 | xor eax, eax ; Print days 103 | mov al, byte [.Days] 104 | push 0x06 105 | int 0x80 106 | 107 | mov al, '/' ; Print separator 108 | push 0x01 109 | int 0x80 110 | 111 | xor eax, eax ; Print months 112 | mov al, byte [.Months] 113 | push 0x06 114 | int 0x80 115 | 116 | mov al, '/' ; Print separator 117 | push 0x01 118 | int 0x80 119 | 120 | mov cl, 4 121 | xor eax, eax ; Print years 122 | mov ax, word [.Years] 123 | push 0x06 124 | int 0x80 125 | 126 | push 0x0D 127 | int 0x80 ; Get cursor coordinates 128 | 129 | add ah, 1 ; X = X + 1 130 | 131 | push 0x0E 132 | int 0x80 ; Set cursor coordinates 133 | 134 | mov cl, 2 135 | xor eax, eax ; Print hours 136 | mov al, byte [.Hours] 137 | push 0x06 138 | int 0x80 139 | 140 | mov al, ':' ; Print separator 141 | push 0x01 142 | int 0x80 143 | 144 | xor eax, eax ; Print minutes 145 | mov al, byte [.Minutes] 146 | push 0x06 147 | int 0x80 148 | 149 | mov al, ':' ; Print separator 150 | push 0x01 151 | int 0x80 152 | 153 | xor eax, eax ; Print seconds 154 | mov al, byte [.Seconds] 155 | push 0x06 156 | int 0x80 157 | 158 | push 0x03 ; Next line 159 | int 0x80 160 | 161 | jmp .loop 162 | 163 | .summary: 164 | 165 | mov si, .totalbytes_msg 166 | push 0x02 167 | int 0x80 168 | 169 | mov eax, dword [.TotalSize] 170 | xor cl, cl 171 | xor dl, dl 172 | push 0x06 173 | int 0x80 174 | 175 | mov si, .dot_msg 176 | push 0x02 177 | int 0x80 178 | 179 | xor eax, eax 180 | mov ax, word [.FilesNumber] 181 | xor cl, cl 182 | xor dl, dl 183 | push 0x06 184 | int 0x80 185 | 186 | mov si, .files_msg 187 | push 0x02 188 | int 0x80 189 | 190 | xor eax, eax 191 | mov ax, word [.DirectoriesNumber] 192 | xor cl, cl 193 | xor dl, dl 194 | push 0x06 195 | int 0x80 196 | 197 | mov si, .dir_msg 198 | push 0x02 199 | int 0x80 200 | 201 | jmp prompt_loop 202 | 203 | 204 | 205 | .Directory db 0x00 206 | .bytes_msg db ' bytes', 0x00 207 | .totalbytes_msg db ' Total bytes: ', 0x00 208 | .dot_msg db '. ', 0x00 209 | .files_msg db ' files, ', 0x00 210 | .dir_msg db ' directories.', 0x0A, 0x00 211 | .EntryCounter dw 0x0000 212 | .Seconds db 0x00 213 | .Minutes db 0x00 214 | .Hours db 0x00 215 | .Days db 0x00 216 | .Months db 0x00 217 | .Years dw 0x0000 218 | .Size dd 0x00000000 219 | .TotalSize dd 0x00000000 220 | .DirectoriesNumber dw 0x0000 221 | .FilesNumber dw 0x0000 222 | .FileName times 13 db 0x00 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /includes/shell/root.inc: -------------------------------------------------------------------------------- 1 | ; **** Root command **** 2 | 3 | root_cmd: 4 | 5 | mov si, command_line_switches 6 | cmp byte [si], 0x00 7 | je .missing_parameter 8 | 9 | push 0x04 ; String to integer 10 | int 0x80 11 | 12 | mov dl, al 13 | push 0x29 ; Set current drive 14 | int 0x80 15 | 16 | jmp prompt_loop ; Return to prompt 17 | 18 | 19 | 20 | .missing_parameter: 21 | 22 | mov si, .missing_parameter_msg 23 | push 0x02 24 | int 0x80 25 | jmp prompt_loop 26 | 27 | 28 | 29 | 30 | 31 | .missing_parameter_msg db 'Required parameter missing: new root (integer).', 0x0A, 0x00 32 | -------------------------------------------------------------------------------- /includes/shell/time.inc: -------------------------------------------------------------------------------- 1 | ; **** Time command **** 2 | 3 | time_cmd: 4 | 5 | push 0x20 ; Read timer 6 | int 0x80 7 | 8 | mov byte [.hours], ch ; Save timer values 9 | mov byte [.minutes], cl 10 | mov byte [.seconds], dh 11 | 12 | xor eax, eax ; Prepare print integer call: not left aligned, print at least 2 chars 13 | xor dl, dl 14 | mov cl, 2 15 | 16 | mov al, byte [.hours] ; Get and print hours 17 | push 0x06 18 | int 0x80 19 | 20 | mov al, ':' ; Print separator 21 | push 0x01 22 | int 0x80 23 | 24 | mov al, byte [.minutes] ; Get and print minutes 25 | push 0x06 26 | int 0x80 27 | 28 | mov al, ':' ; Print separator 29 | push 0x01 30 | int 0x80 31 | 32 | mov al, byte [.seconds] ; Get and print seconds 33 | push 0x06 34 | int 0x80 35 | 36 | push 0x03 ; New line 37 | int 0x80 38 | 39 | jmp prompt_loop ; Return to prompt 40 | 41 | .hours db 0x00 42 | .minutes db 0x00 43 | .seconds db 0x00 44 | -------------------------------------------------------------------------------- /includes/shell/ver.inc: -------------------------------------------------------------------------------- 1 | ; **** Ver command **** 2 | 3 | ver_cmd: 4 | 5 | mov edi, .version 6 | 7 | push 0x87 ; Get version number 8 | int 0x80 9 | 10 | mov esi, .version 11 | 12 | push 0x02 13 | int 0x80 14 | push 0x03 15 | int 0x80 16 | 17 | jmp prompt_loop ; Return to prompt 18 | 19 | .version times 16 db 0x00 20 | -------------------------------------------------------------------------------- /kernel/external/allocate_mem32.inc: -------------------------------------------------------------------------------- 1 | allocate_mem32: 2 | 3 | ; ***************************************************************** 4 | ; Handles a program's request for memory in extended memory 5 | ; ***************************************************************** 6 | 7 | ; IN: EAX --> Amount of memory to allocate 8 | 9 | ; OUT: ECX --> Beginning of allocated memory (flat address relative to program segment) 10 | 11 | push eax 12 | push gs 13 | 14 | mov cx, KernelSpace ; Point GS to kernel 15 | mov gs, cx 16 | 17 | mov ecx, dword [gs:TopMemory] ; Retrieve current top of used memory 18 | add dword [gs:TopMemory], eax ; Allocate memory 19 | 20 | xor eax, eax 21 | mov ax, ds 22 | shl eax, 4 23 | 24 | sub ecx, eax 25 | 26 | pop gs 27 | pop eax 28 | iret 29 | -------------------------------------------------------------------------------- /kernel/external/allocate_memory.inc: -------------------------------------------------------------------------------- 1 | allocate_memory: 2 | 3 | ; ********************************************** 4 | ; Handles a program's request for memory 5 | ; ********************************************** 6 | 7 | ; IN: AX --> Amount of memory to allocate 8 | 9 | ; OUT: CX --> Allocated segment (for data segment registers) 10 | 11 | push ax 12 | push gs 13 | 14 | mov cx, KernelSpace ; Point GS to kernel 15 | mov gs, cx 16 | 17 | mov cx, word [gs:TopSegment] ; Retrieve current top of used memory 18 | shr ax, 4 ; Get memory size in 16 byte blocks 19 | inc ax ; Adjust AX 20 | add word [gs:TopSegment], ax ; Allocate memory 21 | 22 | pop gs 23 | pop ax 24 | iret 25 | -------------------------------------------------------------------------------- /kernel/external/ascii_dump.inc: -------------------------------------------------------------------------------- 1 | ; **************************************************************** 2 | ; Prints a sequence of ASCII chars from ESI, length in ECX 3 | ; **************************************************************** 4 | 5 | ascii_dump: 6 | 7 | push ax 8 | push ecx 9 | push esi 10 | 11 | .loop: 12 | 13 | a32 o32 lodsb ; Byte from ESI 14 | push 0x01 15 | int 0x80 16 | a32 o32 loop .loop ; Loop 17 | 18 | .done: 19 | 20 | pop esi 21 | pop ecx 22 | pop ax 23 | iret 24 | -------------------------------------------------------------------------------- /kernel/external/beep.inc: -------------------------------------------------------------------------------- 1 | beep: 2 | 3 | ; *********************************** 4 | ; ECX = Frequency of the beep 5 | ; *********************************** 6 | 7 | push eax 8 | push ebx 9 | push ecx 10 | push edx 11 | 12 | ; Prepare PIC 13 | 14 | mov al, 0xB6 15 | out 0x43, al 16 | 17 | ; Divide 1193180 / frequency 18 | 19 | mov eax, 1193180 20 | xor edx, edx 21 | div ecx 22 | 23 | ; Correct value now in AX, output it 24 | 25 | out 0x42, al ; Output low byte 26 | mov al, ah 27 | out 0x42, al ; Output high byte 28 | 29 | in al, 0x61 ; Connect speaker to timer 2 30 | or al, 00000011b 31 | 32 | out 0x61, al 33 | 34 | pop edx 35 | pop ecx 36 | pop ebx 37 | pop eax 38 | iret 39 | -------------------------------------------------------------------------------- /kernel/external/center_print_string.inc: -------------------------------------------------------------------------------- 1 | ; *********************************************************************** 2 | ; Prints a 0x00 terminated string in ESI at the center of the row 3 | ; *********************************************************************** 4 | 5 | center_print_string: 6 | 7 | push ax 8 | push bx 9 | push ecx 10 | push dx 11 | 12 | push 0x09 13 | int 0x80 ; Find length of string 14 | 15 | mov ax, 80 ; 80 - length 16 | sub ax, cx 17 | xor dx, dx 18 | mov bx, 2 19 | div bx ; divide / 2 20 | mov dx, ax 21 | push 0x0D 22 | int 0x80 23 | mov ah, dl 24 | push 0x0E 25 | int 0x80 26 | push 0x02 27 | int 0x80 28 | 29 | .done: 30 | 31 | pop dx 32 | pop ecx 33 | pop bx 34 | pop ax 35 | iret 36 | -------------------------------------------------------------------------------- /kernel/external/clear_frame_buffer.inc: -------------------------------------------------------------------------------- 1 | clear_frame_buffer: 2 | 3 | push ax 4 | push ecx 5 | push edi 6 | push es 7 | 8 | xor ax, ax ; Clear frame buffer 9 | mov es, ax 10 | 11 | mov edi, FrameBuffer 12 | 13 | xor al, al 14 | xor ecx, ecx 15 | not cx 16 | 17 | a32 o32 rep stosb 18 | 19 | pop es 20 | pop edi 21 | pop ecx 22 | pop ax 23 | iret 24 | -------------------------------------------------------------------------------- /kernel/external/compare_strings.inc: -------------------------------------------------------------------------------- 1 | compare_strings: 2 | 3 | ; Compares 2 strings (0x00 terminated). 4 | ; strings in DS:ESI and ES:EDI 5 | ; returns DL = 0x01 if equal 0x00 if not 6 | 7 | push ax 8 | push esi 9 | push edi 10 | .loop: 11 | a32 o32 lodsb 12 | mov ah, byte [es:edi] 13 | inc edi 14 | cmp al, ah 15 | jne .not_equal 16 | test al, al 17 | jz .equal 18 | jmp .loop 19 | 20 | .not_equal: 21 | xor dl, dl 22 | jmp .done 23 | 24 | .equal: 25 | mov dl, 0x01 26 | 27 | .done: 28 | pop edi 29 | pop esi 30 | pop ax 31 | iret 32 | -------------------------------------------------------------------------------- /kernel/external/cut_string.inc: -------------------------------------------------------------------------------- 1 | cut_string: 2 | 3 | ; Cuts a string at the desired spot, and adds a terminator 4 | 5 | ; IN: DS:ESI = string to cut 6 | ; BL = character to cut at 7 | 8 | ; OUT: DS:ESI = string cut 9 | ; DS:EBX = starting position of the second part of the string 10 | 11 | push ax 12 | push esi 13 | 14 | .loop: 15 | a32 o32 lodsb 16 | cmp al, bl 17 | je .cut_string 18 | test al, al 19 | jz .fail 20 | jmp .loop 21 | 22 | .cut_string: 23 | dec esi 24 | xor al, al 25 | mov byte [ds:esi], al 26 | inc esi 27 | jmp .done 28 | 29 | .fail: 30 | dec esi 31 | 32 | .done: 33 | mov ebx, esi 34 | pop esi 35 | pop ax 36 | iret 37 | -------------------------------------------------------------------------------- /kernel/external/directory_scanner.inc: -------------------------------------------------------------------------------- 1 | directory_scanner: 2 | 3 | ; ************************************************** 4 | ; Scans the content of the current directory 5 | ; ************************************************** 6 | 7 | ; IN: 8 | ; ax --> Directory entry number 9 | 10 | ; OUT: 11 | ; ax --> Raw time 12 | ; bx --> Raw date 13 | ; es:di --> File name 14 | ; ecx --> Size 15 | ; dh --> Directory flag (0x00 if file, 0xFF if directory) 16 | ; dl --> 0xFF if entry not found, 0x00 if found 17 | 18 | push si 19 | push di 20 | push ds 21 | push es 22 | 23 | mov bx, KernelSpace 24 | mov ds, bx 25 | 26 | mov word [.EntryNumber], ax 27 | mov word [.TargetBuffer], di 28 | mov ax, es 29 | mov word [.TargetSegment], ax 30 | mov word [.EntryCounter], 0x0000 31 | 32 | mov es, bx 33 | 34 | mov si, CurrentDirectoryCache 35 | 36 | .next_entry: 37 | 38 | mov di, .FatNameBuffer 39 | lodsb ; Byte from the directory table, first of entry 40 | dec si 41 | test al, al ; End of table? 42 | jz .failure 43 | 44 | mov cx, 11 45 | rep movsb 46 | xor al, al 47 | stosb 48 | 49 | ; Check for special reserved entries 50 | 51 | mov al, byte [si-11] ; Check for deleted entry 52 | cmp al, 0xE5 53 | je .skip_entry 54 | 55 | mov al, byte [si] ; Check for a vfat entry (ignore it) 56 | cmp al, 0x0F 57 | je .skip_entry 58 | 59 | mov al, byte [si] ; Check for a dir entry 60 | and al, 0x10 61 | jz .no_directory 62 | mov byte [.DirectoryFlag], 0xFF 63 | jmp .directory_check_done 64 | .no_directory: 65 | mov byte [.DirectoryFlag], 0x00 66 | .directory_check_done: 67 | 68 | mov ax, word [si+11] ; Get time 69 | mov word [.RawTime], ax 70 | 71 | mov ax, word [si+13] ; Get date 72 | mov word [.RawDate], ax 73 | 74 | mov eax, dword [si+17] ; Get size 75 | mov dword [.FileSize], eax 76 | 77 | mov ax, word [.EntryNumber] 78 | cmp word [.EntryCounter], ax 79 | je .success 80 | 81 | inc word [.EntryCounter] 82 | 83 | .skip_entry: 84 | 85 | add si, 21 ; Get to the next entry 86 | jmp .next_entry 87 | 88 | 89 | .failure: 90 | 91 | xor dl, dl 92 | not dl 93 | jmp .done 94 | 95 | .success: 96 | 97 | mov si, .FatNameBuffer ; Convert name 98 | mov di, word [.TargetBuffer] 99 | mov ax, word [.TargetSegment] 100 | mov es, ax 101 | 102 | call fat_name_to_string 103 | 104 | xor dl, dl 105 | 106 | .done: 107 | 108 | mov dh, byte [.DirectoryFlag] 109 | mov ax, word [.RawTime] 110 | mov bx, word [.RawDate] 111 | mov ecx, dword [.FileSize] 112 | 113 | pop es 114 | pop ds 115 | pop di 116 | pop si 117 | iret 118 | 119 | 120 | 121 | .DirectoryFlag db 0x00 122 | .EntryNumber dw 0x0000 123 | .EntryCounter dw 0x0000 124 | .TargetBuffer dw 0x0000 125 | .TargetSegment dw 0x0000 126 | .RawDate dw 0x0000 127 | .RawTime dw 0x0000 128 | .FileSize dd 0x00000000 129 | .FatNameBuffer times 12 db 0x00 130 | -------------------------------------------------------------------------------- /kernel/external/disable_cursor.inc: -------------------------------------------------------------------------------- 1 | ; ********************************************* 2 | ; Disables (hides) the text mode cursor 3 | ; ********************************************* 4 | 5 | disable_cursor: 6 | 7 | push ax 8 | push ds 9 | 10 | mov ax, KernelSpace 11 | mov ds, ax 12 | 13 | call clear_cursor 14 | mov byte [CursorStatus], 0x00 15 | 16 | pop ds 17 | pop ax 18 | 19 | iret 20 | -------------------------------------------------------------------------------- /kernel/external/draw_line.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------------------------------------------------- 2 | ; 3 | ; IN: DL --> Color of pixel 4 | ; BX --> X Starting position 5 | ; CL --> Y Starting position 6 | ; AX --> X Ending position 7 | ; CH --> Y Ending position 8 | draw_line: 9 | push ax 10 | push bx 11 | push cx 12 | push dx 13 | push ds 14 | 15 | ; Point DS to kernel 16 | 17 | push ax 18 | mov ax, KernelSpace 19 | mov ds, ax 20 | pop ax 21 | 22 | ; Using this algorithm from https://en.wikipedia.org/wiki/Bresenham's_line_algorithm 23 | 24 | ; plotLine(x0,y0, x1,y1) 25 | ; dx = x1 - x0 26 | ; dy = y1 - y0 27 | ; D = 2*dy - dx 28 | ; y = y0 29 | 30 | ; for x from x0 to x1 31 | ; plot(x,y) 32 | ; if D > 0 33 | ; y = y + 1 34 | ; D = D - dx 35 | ; end if 36 | ; D = D + dy 37 | 38 | ; Save colour 39 | 40 | mov byte [.Colour], dl 41 | 42 | ; Get "dx" 43 | 44 | mov word [.dx], ax 45 | sub word [.dx], bx 46 | 47 | ; Get "dy" 48 | 49 | push cx 50 | xor cl, cl 51 | shr cx, 8 52 | mov word [.dy], cx 53 | pop cx 54 | push cx 55 | xor ch, ch 56 | sub word [.dy], cx 57 | pop cx 58 | 59 | ; Get "D" 60 | 61 | push ax 62 | push bx 63 | mov ax, word [.dy] 64 | mov bx, 2 65 | mul bx 66 | sub ax, word [.dx] 67 | mov word [.D], ax 68 | pop bx 69 | pop ax 70 | 71 | ; For x from x0 to x1 72 | 73 | .loop: 74 | cmp bx, ax 75 | je .done 76 | inc bx 77 | 78 | 79 | ; plot(x,y) 80 | 81 | mov dl, byte [.Colour] 82 | push 0x81 83 | int 0x80 84 | 85 | 86 | ; if D > 0 87 | 88 | cmp word [.D], 0x0000 89 | jg .do_stuff 90 | .stuff_done: 91 | 92 | ; end if 93 | ; D = D + dy 94 | 95 | mov dx, word [.dy] 96 | add word [.D], dx 97 | jmp .loop 98 | 99 | ; y = y + 1 100 | ; D = D - dx 101 | 102 | .do_stuff: 103 | inc cl 104 | mov dx, word [.D] 105 | sub dx, word [.dx] 106 | mov word [.D], dx 107 | jmp .stuff_done 108 | 109 | 110 | .done: 111 | pop ds 112 | pop dx 113 | pop cx 114 | pop bx 115 | pop ax 116 | iret 117 | 118 | 119 | .Colour db 0x00 120 | .D dw 0x0000 121 | .dx dw 0x0000 122 | .dy dw 0x0000 123 | -------------------------------------------------------------------------------- /kernel/external/draw_pixel.inc: -------------------------------------------------------------------------------- 1 | ;---------------------------------------------------------------------- 2 | ; 3 | ; IN: DL --> Color of pixel 4 | ; BX --> X Position 5 | ; CL --> Y Position 6 | 7 | draw_pixel: 8 | push eax 9 | push ebx 10 | push ecx 11 | push edx 12 | push es 13 | push edi 14 | 15 | push dx 16 | 17 | xor eax, eax ; Point ES to a flat segment 18 | mov es, ax 19 | 20 | mov edi, FrameBuffer ; Point EDI to frame buffer 21 | 22 | mov ax, 320 ; Multiply Y by 320 23 | xor ch, ch 24 | mul cx 25 | add edi, eax ; Add to frame buffer location 26 | 27 | and ebx, 0x0000FFFF 28 | 29 | add edi, ebx ; Add the X coordinate 30 | 31 | pop dx 32 | 33 | mov byte [es:edi], dl ; Set the pixel to the color specified 34 | 35 | pop edi 36 | pop es 37 | pop edx 38 | pop ecx 39 | pop ebx 40 | pop eax 41 | iret 42 | -------------------------------------------------------------------------------- /kernel/external/draw_sprite.inc: -------------------------------------------------------------------------------- 1 | ; ********************************************** 2 | ; Draws a sprite from a formatted sprite 3 | ; ********************************************** 4 | 5 | ; IN: DS:SI --> Location of the sprite data 6 | ; BX --> X location of where to print it 7 | ; CL --> Y location of where to print it 8 | 9 | ; SPRITE DATA FORMATTING: 10 | 11 | ; Sprite_X_Length word 12 | ; Sprite_Y_Length byte 13 | ; Sprite_Data: 14 | ; A sequence of bytes indicating the pixel colours 15 | 16 | draw_sprite: 17 | 18 | push ax 19 | push bx 20 | push cx 21 | push dx 22 | push si 23 | push es 24 | 25 | mov ax, KernelSpace 26 | mov es, ax 27 | 28 | mov word [es:.OriginalBX], bx 29 | lodsw 30 | mov word [es:.SpriteX], ax 31 | add word [es:.SpriteX], bx 32 | lodsb 33 | mov byte [es:.SpriteY], al 34 | add byte [es:.SpriteY], cl 35 | 36 | .loop: 37 | lodsb 38 | cmp al, 0xFF 39 | je .compression 40 | mov dl, al 41 | cmp bx, word [es:.SpriteX] 42 | je .next_row 43 | push 0x81 44 | int 0x80 45 | inc bx 46 | jmp .loop 47 | 48 | .next_row: 49 | mov bx, word [es:.OriginalBX] 50 | inc cl 51 | cmp cl, byte [es:.SpriteY] 52 | je .done 53 | push 0x81 54 | int 0x80 55 | inc bx 56 | jmp .loop 57 | 58 | .compression: 59 | mov byte [es:.clValue], cl 60 | lodsw 61 | mov cx, ax 62 | lodsb 63 | mov dl, al 64 | 65 | .compression_loop: 66 | cmp bx, word [es:.SpriteX] 67 | je .compression_next_row 68 | push cx 69 | mov cl, byte [es:.clValue] 70 | push 0x81 71 | int 0x80 72 | pop cx 73 | inc bx 74 | loop .compression_loop 75 | mov cl, byte [es:.clValue] 76 | jmp .loop 77 | 78 | .compression_next_row: 79 | mov bx, word [es:.OriginalBX] 80 | inc byte [es:.clValue] 81 | mov al, byte [es:.clValue] 82 | cmp byte [es:.SpriteY], al 83 | je .done 84 | push cx 85 | mov cl, byte [es:.clValue] 86 | push 0x81 87 | int 0x80 88 | pop cx 89 | inc bx 90 | loop .compression_loop 91 | mov cl, byte [es:.clValue] 92 | jmp .loop 93 | 94 | .done: 95 | 96 | pop es 97 | pop si 98 | pop dx 99 | pop cx 100 | pop bx 101 | pop ax 102 | 103 | iret 104 | 105 | 106 | 107 | .clValue db 0x00 108 | .OriginalBX dw 0x0000 109 | .SpriteX dw 0x0000 110 | .SpriteY db 0x00 111 | -------------------------------------------------------------------------------- /kernel/external/enable_cursor.inc: -------------------------------------------------------------------------------- 1 | ; ******************************************** 2 | ; Enables (shows) the text mode cursor 3 | ; ******************************************** 4 | 5 | enable_cursor: 6 | 7 | push ax 8 | push ds 9 | 10 | mov ax, KernelSpace 11 | mov ds, ax 12 | 13 | call draw_cursor 14 | mov byte [CursorStatus], 0x01 15 | 16 | pop ds 17 | pop ax 18 | 19 | iret 20 | -------------------------------------------------------------------------------- /kernel/external/enter_graphics_mode.inc: -------------------------------------------------------------------------------- 1 | enter_graphics_mode: 2 | push ax 3 | mov al, 0x13 4 | mov ah,00 ;subfunction 0 5 | int 10h ;call graphics interrupt 6 | push 0x85 ; Clear screen 7 | int 0x80 8 | pop ax 9 | iret 10 | -------------------------------------------------------------------------------- /kernel/external/exit_graphics_mode.inc: -------------------------------------------------------------------------------- 1 | exit_graphics_mode: 2 | push ax 3 | push bx 4 | push cx 5 | push dx 6 | 7 | mov al, 0x03 8 | mov ah,00 ;subfunction 0 9 | int 10h ;call graphics interrupt 10 | 11 | 12 | ; Prepare the screen 13 | 14 | mov ax, 0x1003 15 | mov bl, 0x00 16 | xor bh, bh 17 | int 0x10 ; Disable blinking with BIOS 18 | 19 | mov dh, 24 20 | mov dl, 80 21 | mov bh, 0x00 22 | mov ah, 0x02 23 | int 0x10 ; Disable BIOS cursor 24 | 25 | mov ah, 0x02 26 | mov al, 0x70 27 | push 0x11 28 | int 0x80 ; Set palette and reset screen 29 | push 0x0A 30 | int 0x80 31 | 32 | 33 | pop dx 34 | pop cx 35 | pop bx 36 | pop ax 37 | iret 38 | -------------------------------------------------------------------------------- /kernel/external/fat_time_to_integer.inc: -------------------------------------------------------------------------------- 1 | fat_time_to_integer: 2 | 3 | ; Transforms raw FAT time into usable integers 4 | ; AX = FAT time, BX = FAT date 5 | ; Returns: 6 | ; AL = Seconds 7 | ; AH = Minutes 8 | ; BL = Hours 9 | ; BH = Days 10 | ; CL = Months 11 | ; DX = Years 12 | 13 | push ds 14 | 15 | mov dx, KernelSpace 16 | mov ds, dx 17 | 18 | mov word [.RawTime], ax 19 | mov word [.RawDate], bx 20 | 21 | ; Convert seconds 22 | 23 | mov ax, word [.RawTime] 24 | 25 | and ax, 0000000000011111b ; Extract seconds/2 26 | mov bx, 2 ; Seconds*2 27 | mul bx 28 | 29 | mov byte [.Seconds], al ; Save 30 | 31 | ; Convert minutes 32 | 33 | mov ax, word [.RawTime] 34 | 35 | and ax, 0000011111100000b ; Extract minutes 36 | shr ax, 5 ; Adjust it 37 | 38 | mov byte [.Minutes], al ; Save 39 | 40 | ; Convert hours 41 | 42 | mov ax, word [.RawTime] 43 | 44 | and ax, 1111100000000000b ; Extract hours 45 | shr ax, 11 ; Adjust it 46 | 47 | mov byte [.Hours], al ; Save 48 | 49 | ; Convert day 50 | 51 | mov ax, word [.RawDate] 52 | 53 | and ax, 0000000000011111b ; Extract day 54 | 55 | mov byte [.Day], al ; Save 56 | 57 | ; Convert month 58 | 59 | mov ax, word [.RawDate] 60 | 61 | and ax, 0000000111100000b ; Extract month 62 | shr ax, 5 ; Adjust it 63 | 64 | mov byte [.Month], al ; Save 65 | 66 | ; Convert year 67 | 68 | mov ax, word [.RawDate] 69 | 70 | and ax, 1111111000000000b ; Extract year-1980 71 | shr ax, 9 ; Adjust it 72 | add ax, 1980 ; Add 1980 73 | 74 | mov word [.Year], ax ; Save 75 | 76 | ; *** Copy results in the proper registers *** 77 | 78 | mov al, byte [.Seconds] 79 | mov ah, byte [.Minutes] 80 | mov bl, byte [.Hours] 81 | mov bh, byte [.Day] 82 | mov cl, byte [.Month] 83 | mov dx, word [.Year] 84 | 85 | pop ds 86 | iret 87 | 88 | .RawDate dw 0x0000 89 | .RawTime dw 0x0000 90 | .Seconds db 0x00 91 | .Minutes db 0x00 92 | .Hours db 0x00 93 | .Day db 0x00 94 | .Month db 0x00 95 | .Year dw 0x0000 96 | -------------------------------------------------------------------------------- /kernel/external/floppy_read_byte.inc: -------------------------------------------------------------------------------- 1 | floppy_read_byte: 2 | 3 | ; *********************************************************** 4 | ; Reads a byte from a specific location from a floppy 5 | ; *********************************************************** 6 | 7 | ; IN: 8 | ; EBX = Byte address 9 | ; DL = Drive number 10 | 11 | ; OUT: 12 | ; AL = Byte read 13 | 14 | push ebx 15 | push ecx 16 | push edx 17 | push ds 18 | push es 19 | 20 | mov cx, KernelSpace ; Prepare DS and ES 21 | mov ds, cx 22 | mov es, cx 23 | 24 | push eax ; Save EAX to save the other parts of the register 25 | 26 | push dx ; Save target drive for later 27 | 28 | ; Calculate the sector where the byte is found 29 | 30 | xor edx, edx ; Prepare EDX 31 | mov eax, ebx ; Put the address in EAX 32 | mov ebx, 512 ; Prepare to divide by 512 33 | div ebx ; Divide! 34 | 35 | mov word [.target_sector], ax 36 | mov word [.target_offset], dx 37 | 38 | pop dx 39 | 40 | ; Check if the cache if useful 41 | 42 | cmp byte [CacheStatus], 0xFF 43 | jne .cache_miss 44 | cmp ax, word [SectorInCache] 45 | jne .cache_miss 46 | cmp dl, byte [DriveInCache] 47 | jne .cache_miss 48 | 49 | .cache_hit: 50 | 51 | ; The sector is already loaded in the cache, read the byte and return 52 | 53 | mov bx, word [.target_offset] 54 | pop eax ; Restore the rest of EAX 55 | add bx, DiskCache 56 | mov al, byte [bx] 57 | jmp .done 58 | 59 | .cache_miss: 60 | 61 | ; The cache is not useful, we need to fetch the sector from the drive 62 | 63 | mov byte [CacheStatus], 0xFF ; Flag cache as enabled 64 | mov ax, word [.target_sector] 65 | mov bx, DiskCache ; Target buffer is cache 66 | mov cx, 1 ; Read 1 sector 67 | push 0x23 68 | int 0x80 ; Read sector 69 | mov word [SectorInCache], ax ; Set cache metadata 70 | mov byte [DriveInCache], dl 71 | jmp .cache_hit ; Now we can use the cache 72 | 73 | .done: 74 | 75 | pop es 76 | pop ds 77 | pop edx 78 | pop ecx 79 | pop ebx 80 | iret 81 | 82 | .target_sector dw 0x0000 83 | .target_offset dw 0x0000 84 | -------------------------------------------------------------------------------- /kernel/external/floppy_read_dword.inc: -------------------------------------------------------------------------------- 1 | floppy_read_dword: 2 | 3 | ; ************************************************************ 4 | ; Reads a dword from a specific location from a floppy 5 | ; ************************************************************ 6 | 7 | ; IN: 8 | ; EBX = Dword address 9 | ; DL = Drive number 10 | 11 | ; OUT: 12 | ; EAX = Dword read 13 | 14 | push ebx 15 | push cx ; Save regs 16 | 17 | add ebx, 3 ; Read last to first byte, since it's little endian 18 | 19 | mov cx, 4 ; Loop 4 times 20 | 21 | .loop: 22 | shl eax, 8 ; Rotate EAX left 23 | push 0x24 ; Read byte call 24 | int 0x80 25 | dec ebx ; Next byte 26 | loop .loop ; Loop! 27 | 28 | pop cx ; Restore regs 29 | pop ebx 30 | 31 | iret 32 | -------------------------------------------------------------------------------- /kernel/external/floppy_read_sectors.inc: -------------------------------------------------------------------------------- 1 | floppy_read_sectors: 2 | 3 | ; ********************************************************** 4 | ; Reads multiple LBA addressed sectors from a floppy 5 | ; ********************************************************** 6 | 7 | ; IN: 8 | ; AX = LBA starting sector 9 | ; DL = Drive number 10 | ; ES = Buffer segment 11 | ; EBX = Buffer offset 12 | ; CX = Sectors count 13 | 14 | push eax ; Save GPRs 15 | push ebx 16 | push ecx 17 | push edx 18 | push esi 19 | push edi 20 | push ds 21 | 22 | mov si, KernelSpace 23 | mov ds, si 24 | 25 | .loop: 26 | 27 | push es 28 | push ebx 29 | 30 | mov si, KernelSpace 31 | mov es, si 32 | 33 | mov byte [CacheStatus], 0xFF 34 | mov byte [DriveInCache], dl 35 | mov word [SectorInCache], ax 36 | mov bx, DiskCache 37 | 38 | call floppy_read_sector ; Read sector 39 | 40 | pop ebx 41 | pop es 42 | 43 | jc .done ; If carry, exit routine 44 | 45 | mov edi, ebx 46 | mov esi, DiskCache 47 | push ecx 48 | mov ecx, 512 49 | a32 o32 rep movsb 50 | pop ecx 51 | 52 | inc ax ; Increment sector 53 | add ebx, 512 ; Increment buffer 54 | 55 | loop .loop ; Loop! 56 | 57 | .done: 58 | pop ds 59 | pop edi 60 | pop esi 61 | pop edx 62 | pop ecx ; Restore GPRs 63 | pop ebx 64 | pop eax 65 | iret ; Exit routine 66 | -------------------------------------------------------------------------------- /kernel/external/floppy_read_word.inc: -------------------------------------------------------------------------------- 1 | floppy_read_word: 2 | 3 | ; *********************************************************** 4 | ; Reads a word from a specific location from a floppy 5 | ; *********************************************************** 6 | 7 | ; IN: 8 | ; EBX = Word address 9 | ; DL = Drive number 10 | 11 | ; OUT: 12 | ; AX = Word read 13 | 14 | inc ebx ; Read last to first byte, since it's little endian 15 | push 0x24 ; Read byte call 16 | int 0x80 17 | mov ah, al ; Put the higher byte in AH 18 | dec ebx ; Next byte 19 | push 0x24 ; Read byte call 20 | int 0x80 21 | 22 | iret 23 | -------------------------------------------------------------------------------- /kernel/external/floppy_write_byte.inc: -------------------------------------------------------------------------------- 1 | floppy_write_byte: 2 | 3 | ; ******************************************************** 4 | ; Writes a byte to a specific location on a floppy 5 | ; ******************************************************** 6 | 7 | ; IN: 8 | ; AL = Byte to write 9 | ; EBX = Byte address 10 | ; DL = Drive number 11 | 12 | push eax 13 | push ebx 14 | push ecx 15 | push edx 16 | push ds 17 | push es 18 | 19 | mov cx, KernelSpace ; Prepare DS and ES 20 | mov ds, cx 21 | mov es, cx 22 | 23 | mov byte [.ByteToWrite], al ; Save byte to write for later 24 | 25 | push dx ; Save target drive for later 26 | 27 | ; Calculate the sector where the byte is found 28 | 29 | xor edx, edx ; Prepare EDX 30 | mov eax, ebx ; Put the address in EAX 31 | mov ebx, 512 ; Prepare to divide by 512 32 | div ebx ; Divide! 33 | 34 | mov word [.target_sector], ax 35 | mov word [.target_offset], dx 36 | 37 | pop dx 38 | 39 | ; Check if the cache if useful 40 | 41 | cmp byte [CacheStatus], 0xFF 42 | jne .cache_miss 43 | cmp ax, word [SectorInCache] 44 | jne .cache_miss 45 | cmp dl, byte [DriveInCache] 46 | jne .cache_miss 47 | 48 | .cache_hit: 49 | 50 | ; The sector is already loaded in the cache, write the byte 51 | 52 | mov bx, word [.target_offset] 53 | add bx, DiskCache 54 | mov al, byte [.ByteToWrite] 55 | mov byte [bx], al 56 | jmp .write_cache 57 | 58 | .cache_miss: 59 | 60 | ; The cache is not useful, we need to fetch the sector from the drive 61 | 62 | mov byte [CacheStatus], 0xFF ; Flag cache as enabled 63 | mov ax, word [.target_sector] 64 | mov bx, DiskCache ; Target buffer is cache 65 | mov cx, 1 ; Read 1 sector 66 | push 0x23 67 | int 0x80 ; Read sector 68 | mov word [SectorInCache], ax ; Set cache metadata 69 | mov byte [DriveInCache], dl 70 | jmp .cache_hit ; Now we can use the cache 71 | 72 | .write_cache: 73 | 74 | ; Write the cache back onto the disk 75 | 76 | mov ax, [SectorInCache] 77 | mov dl, [DriveInCache] 78 | mov bx, DiskCache 79 | mov cx, 1 80 | push 0x31 81 | int 0x80 82 | 83 | pop es 84 | pop ds 85 | pop edx 86 | pop ecx 87 | pop ebx 88 | pop eax 89 | iret 90 | 91 | .ByteToWrite db 0x00 92 | .target_sector dw 0x0000 93 | .target_offset dw 0x0000 94 | -------------------------------------------------------------------------------- /kernel/external/floppy_write_dword.inc: -------------------------------------------------------------------------------- 1 | floppy_write_dword: 2 | 3 | ; ********************************************************* 4 | ; Writes a dword to a specific location on a floppy 5 | ; ********************************************************* 6 | 7 | ; IN: 8 | ; EAX = Dword to write 9 | ; EBX = Dword address 10 | ; DL = Drive number 11 | 12 | push eax 13 | push ebx 14 | push cx ; Save regs 15 | 16 | mov cx, 4 ; Loop 4 times 17 | 18 | .loop: 19 | push 0x32 ; Write byte call 20 | int 0x80 21 | shr eax, 8 ; Rotate EAX right 22 | inc ebx ; Next byte 23 | loop .loop ; Loop! 24 | 25 | pop cx ; Restore regs 26 | pop ebx 27 | pop eax 28 | 29 | iret 30 | -------------------------------------------------------------------------------- /kernel/external/floppy_write_sectors.inc: -------------------------------------------------------------------------------- 1 | floppy_write_sectors: 2 | 3 | ; ********************************************************* 4 | ; Writes multiple LBA addressed sectors to a floppy 5 | ; ********************************************************* 6 | 7 | ; IN: 8 | ; AX = LBA starting sector 9 | ; DL = Drive number 10 | ; ES = Buffer segment 11 | ; BX = Buffer offset 12 | ; CX = Sectors count 13 | 14 | push ax ; Save GPRs 15 | push bx 16 | push cx 17 | push dx 18 | 19 | .loop: 20 | 21 | call floppy_write_sector ; Write sector 22 | jc .done ; If carry, exit routine 23 | 24 | inc ax ; Increment sector 25 | add bx, 512 ; Add 512 to the buffer 26 | 27 | loop .loop ; Loop! 28 | 29 | .done: 30 | pop dx 31 | pop cx ; Restore GPRs 32 | pop bx 33 | pop ax 34 | iret ; Exit routine 35 | -------------------------------------------------------------------------------- /kernel/external/floppy_write_word.inc: -------------------------------------------------------------------------------- 1 | floppy_write_word: 2 | 3 | ; ******************************************************** 4 | ; Writes a word to a specific location on a floppy 5 | ; ******************************************************** 6 | 7 | ; IN: 8 | ; AX = Word to write 9 | ; EBX = Word address 10 | ; DL = Drive number 11 | 12 | push ax 13 | 14 | xchg al, ah 15 | inc ebx ; Write last to first byte, since it's little endian 16 | push 0x32 ; Write byte call 17 | int 0x80 18 | xchg al, ah 19 | dec ebx ; Next byte 20 | push 0x32 ; Write byte call 21 | int 0x80 22 | 23 | pop ax 24 | 25 | iret 26 | -------------------------------------------------------------------------------- /kernel/external/get_char.inc: -------------------------------------------------------------------------------- 1 | ; **************************************** 2 | ; Gets a char from keyboard (stub) 3 | ; **************************************** 4 | 5 | ; Returns: AL = ASCII char 6 | 7 | get_char: 8 | 9 | push ds 10 | push ax 11 | 12 | mov ax, KernelSpace 13 | mov ds, ax 14 | 15 | xor ax, ax 16 | int 0x16 17 | 18 | mov byte [.ReturnASCII], al 19 | 20 | pop ax 21 | 22 | mov al, byte [.ReturnASCII] 23 | 24 | pop ds 25 | 26 | iret 27 | 28 | .ReturnASCII db 0x00 29 | -------------------------------------------------------------------------------- /kernel/external/get_current_dir.inc: -------------------------------------------------------------------------------- 1 | get_current_dir: 2 | 3 | ; ****************************************** 4 | ; Returns the current path in ES:EDI 5 | ; ****************************************** 6 | 7 | push esi 8 | push ds 9 | 10 | mov si, KernelSpace 11 | mov ds, si 12 | 13 | mov esi, CurrentDirectoryPath 14 | push 0x27 15 | int 0x80 16 | 17 | pop ds 18 | pop esi 19 | iret 20 | -------------------------------------------------------------------------------- /kernel/external/get_current_drive.inc: -------------------------------------------------------------------------------- 1 | get_current_drive: 2 | 3 | ; ******************************************* 4 | ; Get default drive set in the kernel 5 | ; ******************************************* 6 | 7 | ; IN: Nothing 8 | 9 | ; OUT: DL --> current drive 10 | 11 | push ax 12 | push ds 13 | 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | 17 | mov dl, byte [CurrentDrive] 18 | 19 | pop ds 20 | pop ax 21 | iret 22 | -------------------------------------------------------------------------------- /kernel/external/get_current_palette.inc: -------------------------------------------------------------------------------- 1 | ; *********************************** 2 | ; Returns the current palette 3 | ; *********************************** 4 | 5 | ; OUT: AH = Char palette 6 | ; AL = Cursor palette 7 | 8 | get_current_palette: 9 | 10 | push ds 11 | 12 | mov ax, KernelSpace 13 | mov ds, ax 14 | 15 | mov ah, byte [CharAttributes] 16 | mov al, byte [CursorAttributes] 17 | 18 | pop ds 19 | 20 | iret 21 | -------------------------------------------------------------------------------- /kernel/external/get_cursor_position.inc: -------------------------------------------------------------------------------- 1 | ; ************************************************************ 2 | ; Returns the current position of the text mode cursor 3 | ; ************************************************************ 4 | 5 | get_cursor_position: 6 | 7 | ; OUT: AH = cursor X 8 | ; AL = cursor Y 9 | 10 | push bx 11 | push cx 12 | push dx 13 | push ds 14 | 15 | mov ax, KernelSpace 16 | mov ds, ax 17 | 18 | mov ax, word [CursorLocation] 19 | mov bx, 160 ; Divide AX / 160 20 | xor dx, dx 21 | div bx 22 | xor ah, ah ; Clear AH 23 | push ax ; Push result, for now 24 | mov ax, dx ; Load MOD 25 | mov bx, 2 ; Divide MOD / 2 26 | xor dx, dx 27 | div bx 28 | mov dx, ax ; Result in DX 29 | pop ax ; Restore AX 30 | mov ah, dl ; Move AH 31 | 32 | pop ds 33 | pop dx 34 | pop cx 35 | pop bx 36 | 37 | iret 38 | -------------------------------------------------------------------------------- /kernel/external/get_version_number.inc: -------------------------------------------------------------------------------- 1 | ; ***************************************** 2 | ; Returns the version of the kernel 3 | ; ***************************************** 4 | 5 | ; OUT: ES:EDI --> version number string in ASCII 6 | 7 | get_version_number: 8 | 9 | push esi 10 | push ds 11 | 12 | mov si, KernelSpace 13 | mov ds, si 14 | 15 | mov esi, Version 16 | 17 | push 0x27 18 | int 0x80 19 | 20 | pop ds 21 | pop esi 22 | iret 23 | -------------------------------------------------------------------------------- /kernel/external/initialise_screen.inc: -------------------------------------------------------------------------------- 1 | ; ***************************************************************** 2 | ; Clears the screen (text mode) to the current text palette 3 | ; ***************************************************************** 4 | 5 | initialise_screen: 6 | 7 | push ax 8 | push cx 9 | push di 10 | push ds 11 | push es 12 | 13 | mov ax, 0xB800 14 | mov es, ax 15 | mov ax, KernelSpace 16 | mov ds, ax 17 | 18 | xor di, di ; Point to video memory 19 | 20 | ; Draw prompt (at 0,0) 21 | 22 | mov ah, byte [CursorAttributes] ; Get cursor attributes 23 | mov al, ' ' 24 | stosw 25 | 26 | ; Fill the screen with spaces 27 | 28 | mov ah, byte [CharAttributes] ; Get char attributes 29 | mov al, ' ' 30 | 31 | mov cx, 0x07CF 32 | rep stosw 33 | 34 | ; Set up the variables 35 | 36 | mov word [CursorLocation], 0x0000 37 | mov byte [CursorStatus], 0x01 38 | 39 | pop es 40 | pop ds 41 | pop di 42 | pop cx 43 | pop ax 44 | iret 45 | -------------------------------------------------------------------------------- /kernel/external/input_integer.inc: -------------------------------------------------------------------------------- 1 | input_integer: 2 | 3 | ; Gets a 32-bit integer from keyboard. 4 | ; returns number in EAX 5 | 6 | push ebx 7 | push ecx 8 | push edx 9 | push si 10 | push di 11 | push ds 12 | push es 13 | 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | mov es, ax 17 | 18 | xor cx, cx 19 | xor dx, dx 20 | mov di, .buffer 21 | .loop: 22 | push 0x1C 23 | int 0x80 24 | cmp al, 0x08 25 | je .backspace 26 | cmp al, 0x0D 27 | je .enter 28 | cmp al, '0' 29 | jl .loop 30 | cmp al, '9' 31 | jg .loop 32 | cmp cl, 10 33 | je .loop 34 | inc cl 35 | push 0x01 36 | int 0x80 37 | sub al, '0' 38 | stosb 39 | jmp .loop 40 | .backspace: 41 | cmp cl, 0 42 | je .loop 43 | mov al, 0x08 44 | push 0x01 45 | int 0x80 46 | dec di 47 | dec cl 48 | jmp .loop 49 | .enter: 50 | mov si, .buffer 51 | xor eax, eax 52 | .ascii_to_integer: 53 | cmp cl, 0x00 54 | je .done 55 | mov edx, 10 56 | mul edx 57 | xor edx, edx 58 | mov dl, byte [si] 59 | inc si 60 | add eax, edx 61 | dec cl 62 | jmp .ascii_to_integer 63 | .done: 64 | pop es 65 | pop ds 66 | pop di 67 | pop si 68 | pop edx 69 | pop ecx 70 | pop ebx 71 | iret 72 | .buffer times 10 db 0x00 73 | -------------------------------------------------------------------------------- /kernel/external/input_string.inc: -------------------------------------------------------------------------------- 1 | input_string: 2 | 3 | ; Gets a string from keyboard (0x00 terminated). 4 | ; maximum string length in EBX 5 | ; buffer to save string to in ES:EDI 6 | 7 | push ax 8 | push ebx 9 | push ecx 10 | push edi 11 | 12 | xor ecx, ecx 13 | .loop: 14 | push 0x1C 15 | int 0x80 16 | cmp al, 0x08 17 | je .backspace 18 | cmp al, 0x0D 19 | je .enter 20 | test al, al 21 | jz .loop 22 | cmp ecx, ebx 23 | je .loop 24 | inc ecx 25 | push 0x01 26 | int 0x80 27 | a32 o32 stosb 28 | jmp .loop 29 | .backspace: 30 | test ecx, ecx 31 | jz .loop 32 | mov al, 0x08 33 | push 0x01 34 | int 0x80 35 | dec edi 36 | dec ecx 37 | jmp .loop 38 | .enter: 39 | xor al, al 40 | a32 o32 stosb 41 | pop edi 42 | pop ecx 43 | pop ebx 44 | pop ax 45 | iret 46 | -------------------------------------------------------------------------------- /kernel/external/invalid_cache.inc: -------------------------------------------------------------------------------- 1 | ; ********************************************** 2 | ; Renders the current disk cache invalid 3 | ; ********************************************** 4 | 5 | invalid_cache: 6 | 7 | push ax 8 | push ds 9 | 10 | mov ax, KernelSpace 11 | mov ds, ax 12 | 13 | mov byte [CacheStatus], 0x00 14 | 15 | pop ds 16 | pop ax 17 | iret 18 | -------------------------------------------------------------------------------- /kernel/external/load_dir.inc: -------------------------------------------------------------------------------- 1 | load_dir: 2 | 3 | ; ************************************* 4 | ; Loads a new working directory 5 | ; ************************************* 6 | 7 | ; IN: 8 | ; ds:si --> Directory name 9 | 10 | ; OUT: 11 | ; dl --> 0xFF if failure, cleared on success 12 | 13 | push ax 14 | push bx 15 | push cx 16 | push si 17 | push di 18 | push es 19 | 20 | push dx 21 | 22 | mov ax, KernelSpace 23 | mov es, ax 24 | 25 | mov word [es:.DirName], si 26 | 27 | mov dl, 0x01 28 | push 0x2B ; Get starting cluster and size (directory) 29 | int 0x80 30 | 31 | test al, al 32 | jnz .failure ; Check for success 33 | 34 | mov ax, si 35 | 36 | mov word [es:CurrentDirectoryCluster], ax 37 | 38 | push 0x13 ; Get current drive 39 | int 0x80 40 | 41 | call erase_dir_cache ; Erase the directory cache 42 | mov bx, CurrentDirectoryCache ; Load in the current directory cache 43 | 44 | test ax, ax ; Check if chain points to 0x0000 (root) 45 | jz .load_root 46 | 47 | call fat_load_chain ; Load chain into the buffer 48 | 49 | jmp .success 50 | 51 | .load_root: 52 | 53 | call fat_load_root 54 | jmp .success 55 | 56 | .failure: 57 | 58 | pop dx 59 | 60 | xor dl, dl 61 | not dl 62 | jmp .done 63 | 64 | .success: 65 | 66 | mov si, word [es:.DirName] 67 | 68 | mov di, CurrentDirectoryPath ; Save current path 69 | call path_converter 70 | 71 | pop dx 72 | 73 | xor dl, dl 74 | 75 | .done: 76 | 77 | pop es 78 | pop di 79 | pop si 80 | pop cx 81 | pop bx 82 | pop ax 83 | iret 84 | 85 | .DirName dw 0x0000 86 | -------------------------------------------------------------------------------- /kernel/external/load_file.inc: -------------------------------------------------------------------------------- 1 | load_file: 2 | 3 | ; *********************************************** 4 | ; Loads a file from the current directory 5 | ; *********************************************** 6 | 7 | ; IN: 8 | ; es:bx --> Target segment:offset 9 | ; ds:si --> Must point to a filename (readable format) 10 | 11 | ; OUT: 12 | ; ecx --> File size (in bytes) 13 | ; dl --> 0xFF if failure, cleared on success 14 | 15 | push ax 16 | push bx 17 | push si 18 | push di 19 | push es 20 | push gs 21 | 22 | push dx 23 | 24 | mov cx, es 25 | 26 | mov ax, KernelSpace 27 | mov gs, ax 28 | 29 | mov word [gs:.TargetSegment], cx 30 | mov word [gs:.TargetBuffer], bx 31 | 32 | xor dl, dl 33 | push 0x2B ; Get starting cluster and size (file) 34 | int 0x80 35 | 36 | test al, al 37 | jnz .failure ; Check for success 38 | 39 | mov ax, si 40 | test ax, ax 41 | jz .success ; Check for empty file 42 | 43 | push cx 44 | 45 | mov cx, word [gs:.TargetSegment] 46 | mov es, cx 47 | 48 | mov bx, word [gs:.TargetBuffer] 49 | 50 | push 0x13 ; Get current drive 51 | int 0x80 52 | 53 | call fat_load_chain ; Load chain into the buffer 54 | 55 | pop cx 56 | 57 | jmp .success 58 | 59 | .failure: 60 | 61 | pop dx 62 | 63 | xor dl, dl 64 | not dl 65 | jmp .done 66 | 67 | .success: 68 | 69 | pop dx 70 | 71 | xor dl, dl 72 | 73 | .done: 74 | 75 | pop gs 76 | pop es 77 | pop di 78 | pop si 79 | pop bx 80 | pop ax 81 | iret 82 | 83 | 84 | .TargetSegment dw 0x0000 85 | .TargetBuffer dw 0x0000 86 | -------------------------------------------------------------------------------- /kernel/external/lower_to_uppercase.inc: -------------------------------------------------------------------------------- 1 | lower_to_uppercase: 2 | 3 | ; Transform string to UPPERCASE (0x00 terminated). 4 | ; string in ES:EDI 5 | 6 | push ax 7 | push edi 8 | 9 | .loop: 10 | mov al, byte [es:edi] ; Byte from EDI 11 | cmp al, 0x60 12 | jg .convert 13 | cmp al, 0x00 14 | je .done 15 | .no_convert: 16 | inc edi 17 | jmp .loop 18 | 19 | .convert: 20 | cmp al, 0x7A 21 | jg .no_convert 22 | sub al, 0x20 23 | a32 o32 stosb 24 | jmp .loop 25 | 26 | .done: 27 | pop edi 28 | pop ax 29 | iret 30 | -------------------------------------------------------------------------------- /kernel/external/new_line.inc: -------------------------------------------------------------------------------- 1 | ; ***************************************************** 2 | ; Moves the cursor to the next line (like a \n) 3 | ; ***************************************************** 4 | 5 | new_line: 6 | 7 | push ax 8 | 9 | mov al, 0x0A 10 | push 0x01 11 | int 0x80 12 | 13 | pop ax 14 | iret 15 | -------------------------------------------------------------------------------- /kernel/external/pause.inc: -------------------------------------------------------------------------------- 1 | pause: 2 | 3 | ; Pause the system until a key is pressed. 4 | 5 | push ax 6 | 7 | push 0x1C 8 | int 0x80 9 | 10 | pop ax 11 | iret 12 | -------------------------------------------------------------------------------- /kernel/external/ping_file.inc: -------------------------------------------------------------------------------- 1 | ; ********************************* 2 | ; Gets metadata from a file 3 | ; ********************************* 4 | 5 | ; IN: DS:SI = Relative path 6 | ; DL = 1 for dir, 0 for file 7 | 8 | ; OUT: 9 | ; SI = starting cluster, 0x0000 if not found 10 | ; AL = 0x00 if success, 0xFF if not found 11 | ; BX = raw FAT time 12 | ; ECX = file size 13 | ; DX = raw FAT date 14 | 15 | ping_file: 16 | 17 | push di 18 | push ds 19 | push es 20 | 21 | mov ax, KernelSpace 22 | mov es, ax 23 | 24 | mov byte [es:.DirectoryFlag], dl 25 | 26 | ; Check for root 27 | 28 | lodsb 29 | cmp al, '/' 30 | je .load_root 31 | dec si 32 | 33 | ; Fetch file name 34 | 35 | .loop: 36 | mov di, .FileName 37 | mov cx, 13 38 | 39 | .get_file_name: 40 | lodsb 41 | cmp al, '/' 42 | je .fetch_entry 43 | stosb 44 | test al, al 45 | jz .fetch_target_entry 46 | loop .get_file_name 47 | 48 | .fetch_entry: 49 | xor al, al 50 | stosb 51 | mov dl, 1 ; We're looking for a dir 52 | push si 53 | push ds 54 | mov ax, KernelSpace 55 | mov ds, ax 56 | mov si, .FileName 57 | call fat_get_metadata 58 | mov word [.Cluster], si 59 | pop ds 60 | pop si 61 | cmp al, 0xFF 62 | je .restore 63 | 64 | ; Now temporarily load the fetched dir in the buffer 65 | 66 | call erase_dir_cache 67 | mov ax, word [es:.Cluster] 68 | mov bx, CurrentDirectoryCache 69 | push 0x13 70 | int 0x80 71 | test ax, ax 72 | jz .load_root 73 | call fat_load_chain 74 | jmp .loop 75 | .load_root: 76 | call fat_load_root 77 | jmp .loop 78 | 79 | .fetch_target_entry: 80 | mov dl, byte [es:.DirectoryFlag] 81 | push ax 82 | mov ax, KernelSpace 83 | mov ds, ax 84 | pop ax 85 | mov si, .FileName 86 | call fat_get_metadata 87 | 88 | ; Now restore the old current directory in the buffer 89 | 90 | .restore: 91 | 92 | push ax 93 | push bx 94 | push cx 95 | push dx 96 | push si 97 | push di 98 | 99 | push 0x13 100 | int 0x80 101 | call erase_dir_cache 102 | mov ax, word [CurrentDirectoryCluster] 103 | test ax, ax 104 | jz .load_root_end 105 | mov bx, CurrentDirectoryCache 106 | call fat_load_chain 107 | jmp .load_dir_done 108 | .load_root_end: 109 | call fat_load_root 110 | .load_dir_done: 111 | 112 | pop di 113 | pop si 114 | pop dx 115 | pop cx 116 | pop bx 117 | pop ax 118 | 119 | 120 | .done: 121 | 122 | pop es 123 | pop ds 124 | pop di 125 | iret 126 | 127 | 128 | 129 | .DirectoryFlag db 0x00 130 | .Cluster dw 0x0000 131 | .FileName times 14 db 0x00 132 | -------------------------------------------------------------------------------- /kernel/external/play_music.inc: -------------------------------------------------------------------------------- 1 | play_music: 2 | 3 | ; IN: DS:ESI --> Start address of the music file 4 | ; DL --> Repeat flag 5 | 6 | push cx 7 | push es 8 | 9 | mov cx, KernelSpace 10 | mov es, cx 11 | 12 | mov cx, ds 13 | mov word [es:MusicSegment], cx 14 | mov dword [es:MusicStartAddress], esi 15 | mov dword [es:MusicCurrentNote], esi 16 | mov byte [es:MusicRepeatFlag], dl 17 | 18 | ; Play starting note 19 | 20 | mov cx, word [ds:esi+1] 21 | push 0x22 22 | int 0x80 23 | 24 | mov byte [es:MusicPlayingFlag], 1 25 | 26 | pop es 27 | pop cx 28 | iret 29 | -------------------------------------------------------------------------------- /kernel/external/print_integer.inc: -------------------------------------------------------------------------------- 1 | print_integer: 2 | 3 | ; Prints a 32-bit integer number on screen. 4 | ; number in EAX 5 | ; DL = 1 if right align, 0 if not 6 | ; CL = minimum number of digits to display (pads with ASCII 0s) 7 | 8 | push eax 9 | push ebx 10 | push ecx 11 | push edx 12 | push di 13 | push si 14 | push ds 15 | 16 | mov bx, KernelSpace 17 | mov ds, bx ; Point to kernel space 18 | 19 | xor ch, ch 20 | cmp dl, 1 21 | je .right_align 22 | 23 | mov dl, 0xFF 24 | jmp .main 25 | 26 | .right_align: 27 | mov dl, ' ' 28 | 29 | .main: 30 | push cx 31 | 32 | .clear_buffer: 33 | mov cx, 10 34 | mov di, .buffer 35 | .clear_buffer_loop: 36 | mov byte [di], dl 37 | inc di 38 | loop .clear_buffer_loop 39 | 40 | ; Pad with 0s 41 | 42 | pop cx 43 | test cl, cl 44 | jz .calculate 45 | mov di, (.buffer+9) 46 | .pad: 47 | mov byte [di], '0' 48 | dec di 49 | loop .pad 50 | 51 | .calculate: 52 | mov di, (.buffer+9) 53 | mov byte [di], '0' 54 | .loop: 55 | xor edx, edx 56 | mov ebx, 10 57 | cmp eax, 0x00 58 | je .done 59 | div ebx 60 | add dl, '0' 61 | mov byte [di], dl 62 | dec di 63 | jmp .loop 64 | .done: 65 | mov si, .buffer 66 | push 0x02 67 | int 0x80 68 | 69 | pop ds 70 | pop si 71 | pop di 72 | pop edx 73 | pop ecx 74 | pop ebx 75 | pop eax 76 | iret 77 | .buffer times 10 db 0x00 78 | db 0x00 79 | -------------------------------------------------------------------------------- /kernel/external/print_integer_hex.inc: -------------------------------------------------------------------------------- 1 | print_integer_hex: 2 | 3 | ; Prints a 32-bit integer number on screen in hexadecimal notation. 4 | ; number in EAX 5 | ; DL = 0 if not aligned or 1 if right aligned 6 | 7 | push eax 8 | push ebx 9 | push ecx 10 | push edx 11 | push di 12 | push si 13 | push ds 14 | 15 | mov bx, KernelSpace 16 | mov ds, bx ; Point to kernel space 17 | 18 | cmp dl, 1 19 | je .right_align 20 | 21 | mov dl, 0xFF 22 | jmp .clear_buffer 23 | 24 | .right_align: 25 | mov dl, ' ' 26 | 27 | .clear_buffer: 28 | mov cx, 8 29 | mov di, .buffer 30 | .clear_buffer_loop: 31 | mov byte [di], dl 32 | inc di 33 | loop .clear_buffer_loop 34 | jmp .calculate 35 | 36 | .calculate: 37 | mov di, (.buffer+7) 38 | mov byte [di], '0' 39 | .loop: 40 | xor edx, edx 41 | mov ebx, 16 42 | cmp eax, 0x00 43 | je .done 44 | div ebx 45 | add dl, '0' 46 | cmp dl, '9' 47 | jg .adjust_for_ascii 48 | .adjusted: 49 | mov byte [di], dl 50 | dec di 51 | jmp .loop 52 | .adjust_for_ascii: 53 | add dl, 7 54 | jmp .adjusted 55 | .done: 56 | mov si, .buffer 57 | push 0x02 58 | int 0x80 59 | 60 | pop ds 61 | pop si 62 | pop di 63 | pop edx 64 | pop ecx 65 | pop ebx 66 | pop eax 67 | iret 68 | .buffer times 8 db 0x00 69 | db 0x00 70 | -------------------------------------------------------------------------------- /kernel/external/print_string.inc: -------------------------------------------------------------------------------- 1 | ; ********************************************** 2 | ; Prints a 0x00 terminated string in ESI 3 | ; ********************************************** 4 | 5 | print_string: 6 | 7 | push ax 8 | push esi 9 | 10 | .loop: 11 | 12 | a32 o32 lodsb ; Byte from ESI 13 | test al, al ; Is 0x00? 14 | jz .done ; If yes, done 15 | push 0x01 16 | int 0x80 17 | jmp .loop ; Loop 18 | 19 | .done: 20 | 21 | pop esi 22 | pop ax 23 | iret 24 | -------------------------------------------------------------------------------- /kernel/external/push_frame.inc: -------------------------------------------------------------------------------- 1 | push_frame: 2 | 3 | push ds 4 | push es 5 | push esi 6 | push edi 7 | push ecx 8 | 9 | xor cx, cx 10 | mov ds, cx 11 | mov cx, 0xA000 12 | mov es, cx 13 | 14 | mov esi, FrameBuffer 15 | xor edi, edi 16 | 17 | xor ecx, ecx 18 | not cx 19 | 20 | a32 o32 rep movsb 21 | 22 | pop ecx 23 | pop edi 24 | pop esi 25 | pop es 26 | pop ds 27 | iret 28 | -------------------------------------------------------------------------------- /kernel/external/put_char.inc: -------------------------------------------------------------------------------- 1 | put_char: 2 | 3 | push ax 4 | push bx 5 | push cx 6 | push dx 7 | push es 8 | push fs 9 | 10 | cmp al, 0xFF ; Is 0xFF (null)? 11 | je .done ; Ignore 12 | 13 | test al, al ; Is 0x00 (null)? 14 | jz .done ; Ignore 15 | 16 | mov bx, 0xB800 ; Point ES to video memory 17 | mov es, bx 18 | 19 | mov bx, KernelSpace ; Point FS to kernel space 20 | mov fs, bx 21 | 22 | cmp al, 0x0A ; Is 0x0A? 23 | je .next_line 24 | 25 | cmp al, 0x08 ; Is 0x08? 26 | je .backspace 27 | 28 | cmp al, 0x09 ; Is 0x09? 29 | je .tab 30 | 31 | mov bx, word [fs:CursorLocation] 32 | inc bx 33 | mov ah, byte [fs:CharAttributes] 34 | mov byte [es:bx], ah ; Attributes first to avoid 'ghosting' 35 | dec bx 36 | mov byte [es:bx], al ; Print character 37 | inc bx 38 | inc bx 39 | cmp bx, 0x0FA0 ; End of video memory? 40 | je .scroll_screen_down 41 | mov word [fs:CursorLocation], bx 42 | cmp byte [fs:CursorStatus], 1 ; Check if cursor is enabled 43 | jne .done 44 | call draw_cursor ; Draw cursor 45 | jmp .done 46 | 47 | .tab: 48 | push 0x0D 49 | int 0x80 ; Get cursor coordinates 50 | 51 | xor al, al 52 | shr ax, 8 53 | mov bx, 8 ; Divide X by 8 to get the cell number 54 | xor dx, dx 55 | div bx 56 | 57 | mov cx, 8 58 | sub cx, dx ; Retrieve % 59 | mov al, ' ' ; Fill space with spaces 60 | 61 | .add_tab_loop: 62 | push 0x01 63 | int 0x80 64 | loop .add_tab_loop 65 | 66 | jmp .done 67 | 68 | .next_line: 69 | push 0x0D 70 | int 0x80 ; Get cursor coordinates 71 | xor ah, ah ; Set X to 0 72 | cmp al, 24 ; Last line? 73 | je .scroll_screen_down ; Scroll screen 74 | inc al ; Y + 1 75 | push 0x0E 76 | int 0x80 ; Move cursor! 77 | jmp .done ; Done 78 | 79 | .backspace: 80 | sub word [fs:CursorLocation], 2 81 | mov al, ' ' 82 | push 0x01 83 | int 0x80 84 | cmp byte [fs:CursorStatus], 1 85 | jne .back_no_cursor 86 | call clear_cursor 87 | .back_no_cursor: 88 | sub word [fs:CursorLocation], 2 89 | cmp byte [fs:CursorStatus], 1 90 | jne .done 91 | call draw_cursor 92 | jmp .done 93 | 94 | .scroll_screen_down: 95 | call clear_cursor ; Destroy cursor 96 | mov bx, 160 ; Next line 97 | 98 | .scroll_down_loop: 99 | cmp bx, 0x0FA0 ; Last char? 100 | je .clear_line 101 | mov ax, word [es:bx] ; Get word 102 | mov word [es:bx-160], ax ; Copy to previous line 103 | inc bx 104 | inc bx 105 | jmp .scroll_down_loop 106 | 107 | .clear_line: 108 | sub bx, 160 109 | mov word [fs:CursorLocation], bx ; New cursor location 110 | mov al, byte [fs:CharAttributes] 111 | 112 | .clear_line_loop: 113 | 114 | cmp bx, 0x0FA0 115 | je .clear_line_done 116 | mov byte [es:bx], ' ' 117 | inc bx 118 | mov byte [es:bx], al 119 | inc bx 120 | jmp .clear_line_loop 121 | 122 | .clear_line_done: 123 | 124 | cmp byte [fs:CursorStatus], 1 125 | jne .done 126 | call draw_cursor ; Restore cursor 127 | 128 | .done: 129 | pop fs 130 | pop es 131 | pop dx 132 | pop cx 133 | pop bx 134 | pop ax 135 | iret 136 | 137 | .tab_loop_flag db 0x00 138 | -------------------------------------------------------------------------------- /kernel/external/set_current_drive.inc: -------------------------------------------------------------------------------- 1 | set_current_drive: 2 | 3 | ; ****************************** 4 | ; Sets the current drive 5 | ; ****************************** 6 | 7 | ; IN: DL = drive number 8 | 9 | ; OUT: nothing 10 | 11 | push ax 12 | push ds 13 | 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | 17 | mov byte [CurrentDrive], dl ; Set up the current drive variable 18 | mov word [CurrentDirectoryPath], 0x002F ; Set the current directory path 19 | 20 | call fat_load_root ; Load the root directory 21 | 22 | pop ds 23 | pop ax 24 | iret 25 | -------------------------------------------------------------------------------- /kernel/external/set_cursor_position.inc: -------------------------------------------------------------------------------- 1 | ; *************************************************************** 2 | ; Sets up a new current position for the text mode cursor 3 | ; *************************************************************** 4 | 5 | set_cursor_position: 6 | 7 | ; IN: AH = cursor X 8 | ; AL = cursor Y 9 | 10 | push ax 11 | push bx 12 | push cx 13 | push dx 14 | push ds 15 | 16 | mov bx, KernelSpace 17 | mov ds, bx 18 | 19 | cmp byte [CursorStatus], 0x01 20 | jne .main 21 | call clear_cursor ; Clear cursor 22 | 23 | .main: 24 | 25 | push ax ; Save AX 26 | xor ah, ah ; Clear high 8 27 | mov bx, 160 ; Multiply Y * 160 28 | mul bx 29 | mov word [CursorLocation], ax ; Save for now 30 | pop ax ; Restore AX 31 | xor al, al ; Clear low 8 32 | shr ax, 8 ; Shift right 8 33 | add ax, ax ; Multiply X * 2 34 | add word [CursorLocation], ax ; Add 35 | 36 | cmp byte [CursorStatus], 0x01 37 | jne .done 38 | call draw_cursor ; Draw cursor back 39 | 40 | .done: 41 | 42 | pop ds 43 | pop dx 44 | pop cx 45 | pop bx 46 | pop ax 47 | 48 | iret 49 | -------------------------------------------------------------------------------- /kernel/external/set_palette.inc: -------------------------------------------------------------------------------- 1 | ; ***************************************** 2 | ; Sets up a new (text mode) palette 3 | ; ***************************************** 4 | 5 | ; IN: AH --> character attributes 6 | ; AL --> cursor attributes 7 | 8 | set_palette: 9 | 10 | push bx 11 | push ds 12 | 13 | mov bx, KernelSpace 14 | mov ds, bx 15 | 16 | mov byte [CharAttributes], ah 17 | mov byte [CursorAttributes], al 18 | 19 | cmp byte [CursorStatus], 0x01 20 | jne .done 21 | call draw_cursor 22 | 23 | .done: 24 | 25 | pop ds 26 | pop bx 27 | 28 | iret 29 | -------------------------------------------------------------------------------- /kernel/external/sleep.inc: -------------------------------------------------------------------------------- 1 | sleep: 2 | 3 | ; IN: ECX: Number of ticks of inactivity 4 | 5 | test ecx, ecx 6 | jz .quick_exit 7 | 8 | sti ; Enable back interrupts 9 | 10 | push ax 11 | push ecx 12 | push ds 13 | 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | 17 | add ecx, dword [ClockTicks] ; Find target tick 18 | 19 | .loop: 20 | 21 | cmp dword [ClockTicks], ecx 22 | je .done 23 | jmp .loop 24 | 25 | .done: 26 | 27 | pop ds 28 | pop ecx 29 | pop ax 30 | 31 | cli 32 | 33 | .quick_exit: 34 | iret 35 | -------------------------------------------------------------------------------- /kernel/external/start_new_program.inc: -------------------------------------------------------------------------------- 1 | start_new_program: 2 | 3 | ; ****************************************** 4 | ; Handles the start of a new process 5 | ; ****************************************** 6 | 7 | ; IN: DS:ESI --> Name of new program 8 | ; DS:EDI --> Command line switches 9 | 10 | ; OUT: EAX = 0xFFFFFFFF if error or not found 11 | 12 | push ebx ; Save general purpose registers 13 | push ecx ; (doesn't save AX because it's the exit code register) 14 | push edx 15 | push esi 16 | push edi 17 | push ebp 18 | 19 | push ds ; Save segment registers 20 | push es 21 | push fs 22 | push gs 23 | 24 | mov ax, KernelSpace ; Point GS to kernel 25 | mov gs, ax 26 | 27 | push dword [gs:TopMemory] ; Save extended memory top 28 | push word [gs:TopSegment] ; Save last top of memory in stack 29 | push word [gs:StackSegment] ; Save last stack segment in stack 30 | push dword [gs:StackPointer] ; Save last stack pointer in stack 31 | 32 | mov ax, ss 33 | mov word [gs:StackSegment], ax ; Save new stack segment in RAM 34 | mov dword [gs:StackPointer], esp ; Save new stack pointer in RAM 35 | 36 | mov ax, word [gs:TopSegment] ; Prepare to load program 37 | mov es, ax 38 | mov ebx, 0x0100 ; Load at offset es:00000100 39 | push 0x12 40 | int 0x80 ; Load program 41 | cmp dl, 0xFF 42 | je .drop_out ; If file not found, drop out 43 | cmp ecx, 0x0000FFFF ; Test if program is too big (> 64KB) 44 | jg .drop_out ; If it is, drop out 45 | 46 | ; -- FINALLY: check if the program ends with ".bin", exit if it doesn't -- 47 | 48 | call check_bin_extension 49 | jc .drop_out 50 | 51 | add cx, 0x0100 ; Add the kernel reserved space to the file size 52 | shr cx, 4 ; Shift CX right by 4 bits to get size in 16 bytes blocks 53 | inc cx ; Adjust CX 54 | add word [gs:TopSegment], cx ; Reduce available memory 55 | 56 | mov esi, edi ; DS:EDI in DS:ESI 57 | xor edi, edi ; Prepare ES:EDI to the string copy 58 | 59 | push 0x27 ; Copy string 60 | int 0x80 61 | 62 | mov cx, word [gs:TopSegment] ; Prepare the stack segment 63 | mov ss, cx 64 | mov esp, 0x1f0 ; Prepare the stack pointer 65 | 66 | sti ; Restore interrupts 67 | 68 | add word [gs:TopSegment], 0x20 ; Allocate 512 more bytes for the stack 69 | 70 | mov ds, ax ; Prepare all segment registers (AX was already correctly loaded) 71 | mov fs, ax 72 | mov gs, ax 73 | 74 | push ax ; Prepare stack for retf 75 | push 0x0100 76 | 77 | xor eax, eax ; Flush all GPRs 78 | xor ebx, ebx 79 | xor ecx, ecx 80 | xor edx, edx 81 | xor esi, esi 82 | xor edi, edi 83 | xor ebp, ebp 84 | 85 | retf ; Retf to the program 86 | 87 | .drop_out: 88 | 89 | mov eax, 0xFFFFFFFF ; Set EAX to 0xFFFFFFFF 90 | push 0x00 91 | int 0x80 ; Terminate process instantly 92 | -------------------------------------------------------------------------------- /kernel/external/stop_beep.inc: -------------------------------------------------------------------------------- 1 | stop_beep: 2 | 3 | push ax 4 | 5 | in al, 0x61 ; Disconnect speaker from timer 2 6 | and al, 11111100b 7 | 8 | out 0x61, al 9 | 10 | pop ax 11 | iret 12 | -------------------------------------------------------------------------------- /kernel/external/stop_music.inc: -------------------------------------------------------------------------------- 1 | stop_music: 2 | 3 | push cx 4 | push es 5 | 6 | mov cx, KernelSpace 7 | mov es, cx 8 | 9 | ; Stop speaker 10 | 11 | push 0x1E 12 | int 0x80 13 | 14 | mov byte [es:MusicPlayingFlag], 0 15 | 16 | pop es 17 | pop cx 18 | iret 19 | -------------------------------------------------------------------------------- /kernel/external/string_copy.inc: -------------------------------------------------------------------------------- 1 | string_copy: 2 | 3 | ; Copies a string 4 | ; Input string in DS:ESI, copies into ES:EDI (0x00 terminated) 5 | 6 | push ax 7 | push esi 8 | push edi 9 | 10 | .loop: 11 | a32 o32 lodsb 12 | a32 o32 stosb 13 | test al, al 14 | jz .done 15 | jmp .loop 16 | 17 | .done: 18 | pop edi 19 | pop esi 20 | pop ax 21 | iret 22 | -------------------------------------------------------------------------------- /kernel/external/string_end.inc: -------------------------------------------------------------------------------- 1 | string_end: 2 | 3 | ; Get to the end of the string, ES:EDI will point to the terminator 4 | ; ES:EDI string 5 | 6 | push ax 7 | 8 | .loop: 9 | mov al, byte [es:edi] 10 | test al, al 11 | jz .done 12 | inc edi 13 | jmp .loop 14 | 15 | .done: 16 | pop ax 17 | iret 18 | -------------------------------------------------------------------------------- /kernel/external/string_length.inc: -------------------------------------------------------------------------------- 1 | string_length: 2 | 3 | ; Returns the length of a string (0x00 terminated). 4 | ; string in DS:ESI 5 | ; returns length in ECX 6 | 7 | push ax 8 | push esi 9 | 10 | xor ecx, ecx 11 | .loop: 12 | a32 o32 lodsb ; Byte from ESI 13 | test al, al ; Is 0? 14 | jz .done 15 | inc ecx 16 | jmp .loop 17 | 18 | .done: 19 | pop esi 20 | pop ax 21 | iret 22 | -------------------------------------------------------------------------------- /kernel/external/string_to_integer.inc: -------------------------------------------------------------------------------- 1 | string_to_integer: 2 | 3 | ; Converts a numeric string into an integer 4 | ; Input string in ESI (0x00 terminated) 5 | ; Output integer in EAX 6 | 7 | push ebx 8 | push ecx 9 | push edx 10 | push esi 11 | 12 | xor ecx, ecx ; Prepare ECX 13 | 14 | .loop: 15 | xor eax, eax ; Prepare EAX 16 | a32 o32 lodsb ; Get byte from string 17 | sub al, '0' ; Get integer value 18 | mov dl, byte [esi] ; Check whether this is the last byte in the string 19 | test dl, dl ; Is the string terminated? 20 | jz .done ; If yes, we're done 21 | add ecx, eax ; Add new value to stored result 22 | mov eax, 10 23 | mul ecx ; Multiply result by 10 24 | mov ecx, eax ; Store result back in ECX 25 | jmp .loop ; Loop 26 | 27 | .done: 28 | add ecx, eax ; Add last unit 29 | mov eax, ecx ; Move result into EAX 30 | pop esi 31 | pop edx 32 | pop ecx 33 | pop ebx 34 | iret 35 | -------------------------------------------------------------------------------- /kernel/external/terminate_process.inc: -------------------------------------------------------------------------------- 1 | terminate_process: 2 | 3 | ; ******************************************** 4 | ; Handles the termination of a process 5 | ; ******************************************** 6 | 7 | ; IN: EAX --> exit code of the process 8 | 9 | mov bx, KernelSpace ; Point GS to kernel 10 | mov gs, bx 11 | 12 | mov bx, word [gs:StackSegment] ; Restore last stack 13 | mov ss, bx 14 | mov esp, dword [gs:StackPointer] 15 | 16 | pop dword [gs:StackPointer] ; Restore older stack in RAM 17 | pop word [gs:StackSegment] 18 | 19 | pop word [gs:TopSegment] ; Restore last top segment 20 | pop dword [gs:TopMemory] ; Restore last top memory 21 | 22 | pop gs ; Restore segment registers 23 | pop fs 24 | pop es 25 | pop ds 26 | 27 | pop ebp ; Restore GPRs 28 | pop edi 29 | pop esi 30 | pop edx 31 | pop ecx 32 | pop ebx 33 | 34 | iret ; Return to calling program 35 | -------------------------------------------------------------------------------- /kernel/external/timer_read.inc: -------------------------------------------------------------------------------- 1 | timer_read: 2 | 3 | ; IN = Nothing 4 | ; OUT = CH = hours 5 | ; CL = minutes 6 | ; DH = seconds 7 | ; DL = DST 8 | 9 | ; /// NOTE: the problem with the time is probably due to the fact that it's returned in BCD format 10 | ; We need to add a conversion routine in this function (done by me) 11 | 12 | push ax 13 | 14 | .retry: 15 | clc ; Clear carry flag 16 | mov ah, 0x02 ; Read RTC (Hours, Minutes, Seconds) 17 | int 0x1A ; RTC Call 18 | jc .retry ; If error, retry 19 | 20 | mov al, ch ; Convert hours 21 | call .bcd_to_integer 22 | mov ch, al 23 | mov al, cl ; Minutes 24 | call .bcd_to_integer 25 | mov cl, al 26 | mov al, dh ; And seconds 27 | call .bcd_to_integer 28 | mov dh, al 29 | 30 | pop ax 31 | iret 32 | 33 | .bcd_to_integer: 34 | 35 | ; AL = BCD number, returns integer in AL 36 | 37 | push cx ; Save CX 38 | push ax ; Save AX 39 | and al, 11110000b ; Extract the high nibble of AL 40 | shr al, 4 ; Shift it right by 4 41 | mov cl, 10 ; Multiply by 10 42 | mul cl 43 | pop cx ; Restore AX in CX 44 | and cl, 00001111b ; Extract the low nibble 45 | add al, cl ; And add it back to AL 46 | pop cx ; Restore CX 47 | ret 48 | -------------------------------------------------------------------------------- /kernel/external/upper_to_lowercase.inc: -------------------------------------------------------------------------------- 1 | upper_to_lowercase: 2 | 3 | ; Transform string to LOWERCASE (0x00 terminated). 4 | ; string in ES:EDI 5 | 6 | push ax 7 | push edi 8 | 9 | .loop: 10 | mov al, byte [es:edi] ; Byte from EDI 11 | cmp al, 0x40 12 | jg .convert 13 | cmp al, 0x00 14 | je .done 15 | .no_convert: 16 | inc edi 17 | jmp .loop 18 | 19 | .convert: 20 | cmp al, 0x5A 21 | jg .no_convert 22 | add al, 0x20 23 | a32 o32 stosb 24 | jmp .loop 25 | 26 | .done: 27 | pop edi 28 | pop ax 29 | iret 30 | -------------------------------------------------------------------------------- /kernel/internal/check_bin_extension.inc: -------------------------------------------------------------------------------- 1 | check_bin_extension: 2 | 3 | push ax 4 | push dx 5 | push esi 6 | push edi 7 | 8 | push es 9 | 10 | mov ax, ds ; Convert file name to uppercase 11 | mov es, ax 12 | mov edi, esi 13 | push 0x15 14 | int 0x80 15 | 16 | mov ax, KernelSpace 17 | mov es, ax 18 | 19 | .loop: 20 | a32 o32 lodsb 21 | cmp al, '.' 22 | je .check_extension 23 | test al, al 24 | jz .no_bin 25 | jmp .loop 26 | 27 | .check_extension: 28 | 29 | mov edi, .bin_string 30 | push 0x08 31 | int 0x80 32 | 33 | test dl, dl 34 | jz .no_bin 35 | 36 | .bin: 37 | clc 38 | jmp .done 39 | 40 | .no_bin: 41 | stc 42 | 43 | .done: 44 | 45 | pop es 46 | 47 | pop edi 48 | pop esi 49 | pop dx 50 | pop ax 51 | 52 | ret 53 | 54 | .bin_string db 'BIN', 0x00 55 | -------------------------------------------------------------------------------- /kernel/internal/clear_cursor.inc: -------------------------------------------------------------------------------- 1 | ; ************************* 2 | ; Clears the cursor 3 | ; ************************* 4 | 5 | clear_cursor: 6 | 7 | push ax 8 | push di 9 | push es 10 | push ds 11 | 12 | mov ax, 0xB800 13 | mov es, ax 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | 17 | mov di, word [CursorLocation] 18 | mov al, byte [es:di] 19 | mov ah, byte [CharAttributes] 20 | 21 | stosw 22 | 23 | pop ds 24 | pop es 25 | pop di 26 | pop ax 27 | 28 | ret 29 | -------------------------------------------------------------------------------- /kernel/internal/draw_cursor.inc: -------------------------------------------------------------------------------- 1 | ; ************************ 2 | ; Draws the cursor 3 | ; ************************ 4 | 5 | draw_cursor: 6 | 7 | push ax 8 | push di 9 | push es 10 | push ds 11 | 12 | mov ax, 0xB800 13 | mov es, ax 14 | mov ax, KernelSpace 15 | mov ds, ax 16 | 17 | mov di, word [CursorLocation] 18 | mov al, byte [es:di] 19 | mov ah, byte [CursorAttributes] 20 | 21 | stosw 22 | 23 | pop ds 24 | pop es 25 | pop di 26 | pop ax 27 | 28 | ret 29 | -------------------------------------------------------------------------------- /kernel/internal/erase_dir_cache.inc: -------------------------------------------------------------------------------- 1 | erase_dir_cache: 2 | 3 | push ax 4 | push es 5 | push di 6 | 7 | mov ax, KernelSpace 8 | mov es, ax 9 | 10 | mov di, CurrentDirectoryCache 11 | mov cx, 0x2000 12 | xor ax, ax 13 | 14 | rep stosw 15 | 16 | pop di 17 | pop es 18 | pop ax 19 | ret 20 | -------------------------------------------------------------------------------- /kernel/internal/fat12_delete_chain.inc: -------------------------------------------------------------------------------- 1 | fat12_delete_chain: 2 | 3 | ; *********************************************** 4 | ; Deletes the whole cluster chain (FAT12) 5 | ; *********************************************** 6 | 7 | ; IN: 8 | ; AX - cluster number 9 | ; DL - drive number 10 | ; OUT: Chain will be deleted 11 | 12 | push eax 13 | push ebx 14 | push ecx 15 | push edx 16 | 17 | push ds 18 | 19 | mov cx, KernelSpace ; Point DS to kernel space 20 | mov ds, cx 21 | 22 | mov word [.Cluster], ax ; Save starting cluster 23 | mov byte [.CurrentDrive], dl ; Save current drive 24 | 25 | ; Fetch some metadata from the BPB 26 | 27 | mov ebx, 0x0E ; Address of the Reserved sectors constant 28 | push 0x25 29 | int 0x80 ; Load word from address 30 | 31 | mov word [.StartOfFAT], ax ; Save result 32 | 33 | xor eax, eax ; Get start of FAT in bytes 34 | mov ax, word [.StartOfFAT] 35 | mov ebx, 512 36 | mul ebx 37 | mov dword [.StartOfFATInBytes], eax 38 | 39 | 40 | 41 | ; Delete cluster 42 | 43 | .delete_cluster: 44 | 45 | mov ax, word [.Cluster] ; Divide cluster by 2 46 | mov bx, 2 47 | xor dx, dx 48 | div bx 49 | add ax, word [.Cluster] ; Add this to get CLUSTER*1.5 (12 bit) 50 | xor ebx, ebx 51 | mov bx, ax 52 | 53 | push dx 54 | 55 | add ebx, dword [.StartOfFATInBytes] 56 | mov dl, byte [.CurrentDrive] 57 | push 0x25 58 | int 0x80 ; Fetch cluster 59 | 60 | pop dx 61 | 62 | cmp dx, 1 ; If DX is on, we are on a split byte, and need to fetch 2 bytes, 63 | ; get the high nibble of the first, and add the second * 0x10 64 | je .split_byte 65 | ; Otherwise keep the high 4 bits of AH, clear the rest 66 | push bx 67 | mov bx, ax ; Save next cluster 68 | and bh, 00001111b 69 | mov word [.Cluster], bx 70 | pop bx 71 | and ax, 1111000000000000b 72 | push 0x32 ; Write cluster to the FAT 73 | int 0x80 74 | jmp .end_fetch 75 | 76 | .split_byte: 77 | push bx 78 | mov bx, ax 79 | and bl, 11110000b ; Save next cluster 80 | shr bx, 4 81 | mov word [.Cluster], bx 82 | pop bx 83 | and ax, 0000000000001111b ; Clear everything but low 4 of AL 84 | push 0x32 ; Write cluster to the FAT 85 | int 0x80 86 | 87 | .end_fetch: 88 | 89 | cmp word [.Cluster], 0xFF7 90 | jg .done 91 | jmp .delete_cluster 92 | 93 | .done: 94 | 95 | pop ds 96 | 97 | pop edx 98 | pop ecx 99 | pop ebx 100 | pop eax 101 | 102 | ret 103 | 104 | 105 | .CurrentDrive db 0x00 106 | .Cluster dw 0x0000 107 | .StartOfFAT dw 0x0000 108 | .StartOfFATInBytes dd 0x00000000 109 | -------------------------------------------------------------------------------- /kernel/internal/fat12_load_chain.inc: -------------------------------------------------------------------------------- 1 | fat12_load_chain: 2 | 3 | ; *********************************************************************** 4 | ; Dumps the whole cluster chain (FAT12) into the specified buffer 5 | ; *********************************************************************** 6 | 7 | ; IN: 8 | ; AX - cluster number 9 | ; ES:BX - target buffer 10 | ; DL - drive number 11 | ; OUT: Chain loaded into a buffer 12 | 13 | push eax 14 | push ebx 15 | push ecx 16 | push edx 17 | 18 | push ds 19 | 20 | mov cx, KernelSpace ; Point DS to kernel space 21 | mov ds, cx 22 | 23 | mov word [.Cluster], ax ; Save starting cluster 24 | mov word [.BufferOffset], bx ; Save buffer offset 25 | mov byte [.CurrentDrive], dl ; Save current drive 26 | 27 | ; Fetch some metadata from the BPB 28 | 29 | mov ebx, 0x0D ; Address of the Sectors per cluster constant 30 | push 0x24 31 | int 0x80 ; Load byte from address 32 | 33 | mov byte [.SectorsPerCluster], al 34 | 35 | mov ebx, 0x0E ; Address of the Reserved sectors constant 36 | push 0x25 37 | int 0x80 ; Load word from address 38 | 39 | mov word [.StartOfFAT], ax ; Save result 40 | 41 | mov ebx, 0x10 ; Address of the Number of FATs constant 42 | push 0x24 43 | int 0x80 ; Load word from address 44 | 45 | mov byte [.NumberOfFATs], al ; Save result 46 | 47 | mov ebx, 0x11 ; Address of the Root entries constant 48 | push 0x25 49 | int 0x80 ; Load word from address 50 | 51 | mov word [.RootEntries], ax ; Save result 52 | 53 | mov ebx, 0x16 ; Address of the Sectors per FAT constant 54 | push 0x25 55 | int 0x80 ; Load word from address 56 | 57 | mov word [.SizeOfFAT], ax ; Save result 58 | 59 | ; Get sectors per cluster in bytes 60 | mov ax, word [.SectorsPerCluster] 61 | mov bx, 512 62 | mul bx 63 | mov word [.SectorsPerClusterInBytes], ax 64 | 65 | xor eax, eax ; Get start of FAT in bytes 66 | mov ax, word [.StartOfFAT] 67 | mov ebx, 512 68 | mul ebx 69 | mov dword [.StartOfFATInBytes], eax 70 | 71 | ; Calculate the start and size of the root directory 72 | 73 | ; Start = reserved_sectors + (number_of_FATs * sectors_per_FAT) 74 | ; Size = (root_entries * 32) / bytes_per_sector 75 | 76 | ; Number of fats * sector per fat in AX 77 | 78 | mov ax, word [.SizeOfFAT] 79 | mov bl, byte [.NumberOfFATs] 80 | xor bh, bh 81 | mul bx 82 | 83 | add ax, word [.StartOfFAT] ; Add reserved sectors 84 | 85 | mov word [.StartOfRoot], ax ; Save result in memory 86 | 87 | ; Root entries * 32 88 | 89 | mov ax, 32 90 | mul word [.RootEntries] 91 | 92 | xor dx, dx ; XOR DX for division 93 | div word [.BytesPerSector] 94 | 95 | mov word [.SizeOfRoot], ax ; Save result in memory 96 | 97 | ; Start of data = (Start of root - 2) + size of root 98 | 99 | mov ax, word [.StartOfRoot] 100 | sub ax, 2 ; Subtract 2 to get LBA 101 | add ax, word [.SizeOfRoot] 102 | mov word [.DataStart], ax 103 | 104 | ; Load chain 105 | 106 | mov ax, word [.Cluster] ; Prepare to enter loop 107 | mov bx, word [.BufferOffset] 108 | 109 | .cluster_loop: 110 | 111 | mov dl, byte [.CurrentDrive] ; Retrieve current drive 112 | cmp ax, 0xFF7 ; Is the last cluster? 113 | jg .done ; If yes, we finished 114 | 115 | ; Multiply ax by the sectors per cluster 116 | 117 | mul byte [.SectorsPerCluster] 118 | 119 | add ax, word [.DataStart] ; Add the data start offset 120 | xor cx, cx 121 | mov cl, byte [.SectorsPerCluster] 122 | push 0x23 ; Read! 123 | int 0x80 124 | add bx, word [.SectorsPerClusterInBytes] ; Move buffer up the bytes per cluster size 125 | 126 | push bx 127 | mov ax, word [.Cluster] ; Divide cluster by 2 128 | mov bx, 2 129 | xor dx, dx 130 | div bx 131 | add ax, word [.Cluster] ; Add this to get CLUSTER*1.5 (12 bit) 132 | xor ebx, ebx 133 | mov bx, ax 134 | 135 | push dx 136 | 137 | add ebx, dword [.StartOfFATInBytes] 138 | mov dl, byte [.CurrentDrive] 139 | push 0x25 140 | int 0x80 ; Fetch cluster 141 | 142 | pop dx 143 | 144 | cmp dx, 1 ; If DX is on, we are on a split byte, and need to fetch 2 bytes, 145 | ; get the high nibble of the first, and add the second * 0x10 146 | je .split_byte 147 | ; Otherwise clear the high 4 bits of AH 148 | and ah, 00001111b 149 | jmp .end_fetch 150 | 151 | .split_byte: 152 | and al, 11110000b ; Clear low 4 of AL 153 | shr ax, 4 ; Shift right a nibble 154 | 155 | .end_fetch: 156 | pop bx 157 | mov word [.Cluster], ax ; Save current cluster 158 | jmp .cluster_loop 159 | 160 | .done: 161 | 162 | pop ds 163 | 164 | pop edx 165 | pop ecx 166 | pop ebx 167 | pop eax 168 | 169 | ret 170 | 171 | 172 | .DataStart dw 0x0000 173 | .SizeOfFAT dw 0x0000 174 | .CurrentDrive db 0x00 175 | .Cluster dw 0x0000 176 | .BufferOffset dw 0x0000 177 | .SectorsPerCluster db 0x00 178 | .SectorsPerClusterInBytes dw 0x0000 179 | .StartOfFAT dw 0x0000 180 | .StartOfFATInBytes dd 0x00000000 181 | .NumberOfFATs db 0x00 182 | .StartOfRoot dw 0x0000 183 | .SizeOfRoot dw 0x0000 184 | .RootEntries dw 0x0000 185 | .BytesPerSector dw 512 186 | -------------------------------------------------------------------------------- /kernel/internal/fat_delete_chain.inc: -------------------------------------------------------------------------------- 1 | fat_delete_chain: 2 | 3 | ; ****************************************************************************** 4 | ; Decides whether to use the FAT12 or FAT16 routine, then passes control 5 | ; ****************************************************************************** 6 | 7 | 8 | call fat12_delete_chain 9 | ret 10 | -------------------------------------------------------------------------------- /kernel/internal/fat_get_metadata.inc: -------------------------------------------------------------------------------- 1 | fat_get_metadata: 2 | 3 | ; ***************************************************************** 4 | ; Returns the metadata of an entry in the current directory 5 | ; ***************************************************************** 6 | 7 | ; IN: DS:SI file/dir name 8 | ; DL = 1 for dir, 0 for file 9 | 10 | ; OUT: 11 | ; SI = starting cluster, 0x0000 if not found 12 | ; AL = 0x00 if success, 0xFF if not found 13 | ; BX = raw FAT time 14 | ; ECX = file size 15 | ; DX = raw FAT date 16 | 17 | push di 18 | push ds 19 | push es 20 | 21 | push eax 22 | 23 | mov ax, KernelSpace 24 | mov es, ax 25 | 26 | mov di, .ConvertedName ; Convert to fat name 27 | call string_to_fat_name 28 | 29 | mov ds, ax 30 | 31 | mov byte [.DirectoryFlag], dl 32 | mov byte [.Success], 0x00 33 | 34 | mov di, CurrentDirectoryCache 35 | mov word [.EntryCounter], 0x0000 36 | 37 | .next_entry: 38 | 39 | mov si, .ConvertedName 40 | 41 | inc word [.EntryCounter] 42 | 43 | mov ah, byte [es:di] ; Byte from the directory table, first of entry 44 | test ah, ah ; End of table? 45 | jz .not_found 46 | 47 | mov cx, 11 48 | .check_name_loop: 49 | 50 | lodsb ; Byte from the file name 51 | mov ah, byte [es:di] ; Byte from table 52 | inc di 53 | cmp al, ah 54 | jne .skip_entry 55 | loop .check_name_loop 56 | 57 | ; FILE FOUND!!! 58 | 59 | mov al, byte [di] 60 | and al, 0x10 ; Directory? 61 | jnz .directory 62 | cmp byte [.DirectoryFlag], 0x00 63 | jne .skip_entry 64 | jmp .get_metadata 65 | .directory: 66 | cmp byte [.DirectoryFlag], 0x01 67 | jne .skip_entry 68 | 69 | .get_metadata: 70 | 71 | add di, 11 ; Get raw creation time 72 | mov ax, word [es:di] 73 | mov word [.RawTime], ax 74 | 75 | add di, 2 ; Get raw creation date 76 | mov ax, word [es:di] 77 | mov word [.RawDate], ax 78 | 79 | add di, 2 ; Retrieve starting cluster 80 | mov ax, word [es:di] 81 | mov word [.Cluster], ax 82 | 83 | add di, 2 ; Get file size 84 | mov eax, dword [es:di] 85 | mov dword [.FileSize], eax 86 | 87 | jmp .done 88 | 89 | .skip_entry: 90 | 91 | mov ax, 32 92 | mov di, CurrentDirectoryCache 93 | mul word [.EntryCounter] 94 | add di, ax 95 | jmp .next_entry 96 | 97 | .not_found: 98 | 99 | mov byte [.Success], 0xFF 100 | 101 | .done: 102 | 103 | pop eax 104 | 105 | mov al, byte [.Success] 106 | mov si, word [.Cluster] 107 | mov bx, word [.RawTime] 108 | mov ecx, dword [.FileSize] 109 | mov dx, word [.RawDate] 110 | 111 | pop es 112 | pop ds 113 | pop di 114 | ret 115 | 116 | 117 | .Success db 0x00 118 | .EntryCounter dw 0x0000 119 | .Cluster dw 0x0000 120 | .FileSize dd 0x00000000 121 | .RawDate dw 0x0000 122 | .RawTime dw 0x0000 123 | .DirectoryFlag db 0x00 124 | .ConvertedName times 12 db 0x00 125 | -------------------------------------------------------------------------------- /kernel/internal/fat_load_chain.inc: -------------------------------------------------------------------------------- 1 | fat_load_chain: 2 | 3 | ; ****************************************************************************** 4 | ; Decides whether to use the FAT12 or FAT16 routine, then passes control 5 | ; ****************************************************************************** 6 | 7 | 8 | call fat12_load_chain 9 | ret 10 | -------------------------------------------------------------------------------- /kernel/internal/fat_load_root.inc: -------------------------------------------------------------------------------- 1 | fat_load_root: 2 | 3 | ; ************************************************************** 4 | ; Loads the root directory (/) into the directory buffer 5 | ; ************************************************************** 6 | 7 | ; IN: DL = drive number 8 | 9 | push eax 10 | push ebx 11 | push ecx 12 | push edx 13 | 14 | push ds 15 | push es 16 | 17 | mov ax, KernelSpace 18 | mov ds, ax 19 | mov es, ax 20 | 21 | ; Fetch some metadata from the BPB 22 | 23 | mov byte [.CurrentDrive], dl 24 | 25 | mov ebx, 0x0E ; Address of the Reserved sectors constant 26 | push 0x25 27 | int 0x80 ; Load word from address 28 | 29 | mov word [.StartOfFAT], ax ; Save result 30 | 31 | mov ebx, 0x10 ; Address of the Number of FATs constant 32 | push 0x24 33 | int 0x80 ; Load word from address 34 | 35 | mov byte [.NumberOfFATs], al ; Save result 36 | 37 | mov ebx, 0x11 ; Address of the Root entries constant 38 | push 0x25 39 | int 0x80 ; Load word from address 40 | 41 | mov word [.RootEntries], ax ; Save result 42 | 43 | mov ebx, 0x16 ; Address of the Sectors per FAT constant 44 | push 0x25 45 | int 0x80 ; Load word from address 46 | 47 | mov word [.SizeOfFAT], ax ; Save result 48 | 49 | ; Calculate the start and size of the root directory 50 | 51 | ; Start = reserved_sectors + (number_of_FATs * sectors_per_FAT) 52 | ; Size = (root_entries * 32) / bytes_per_sector 53 | 54 | ; Number of fats * sector per fat in AX 55 | 56 | mov ax, word [.SizeOfFAT] 57 | mov bl, byte [.NumberOfFATs] 58 | xor bh, bh 59 | mul bx 60 | 61 | add ax, word [.StartOfFAT] ; Add reserved sectors 62 | 63 | mov word [.StartOfRoot], ax ; Save result in memory 64 | 65 | ; Root entries * 32 66 | 67 | mov ax, 32 68 | mul word [.RootEntries] 69 | 70 | xor dx, dx ; XOR DX for division 71 | div word [.BytesPerSector] 72 | 73 | mov word [.SizeOfRoot], ax ; Save result in memory 74 | 75 | ; Load root dir into buffer 76 | 77 | mov bx, CurrentDirectoryCache 78 | mov ax, word [.StartOfRoot] ; Load from here 79 | mov cx, word [.SizeOfRoot] ; Load this many sectors 80 | mov dl, byte [.CurrentDrive] ; Retrieve drive 81 | push 0x23 82 | int 0x80 83 | 84 | pop es 85 | pop ds 86 | 87 | pop edx 88 | pop ecx 89 | pop ebx 90 | pop eax 91 | 92 | ret 93 | 94 | .SizeOfFAT dw 0x0000 95 | .CurrentDrive db 0x00 96 | .StartOfFAT dw 0x0000 97 | .NumberOfFATs db 0x00 98 | .StartOfRoot dw 0x0000 99 | .SizeOfRoot dw 0x0000 100 | .RootEntries dw 0x0000 101 | .BytesPerSector dw 512 102 | -------------------------------------------------------------------------------- /kernel/internal/fat_name_to_string.inc: -------------------------------------------------------------------------------- 1 | fat_name_to_string: 2 | 3 | ; Trasform FAT file name (ex. 'PHOTO IMG') to a readable format (ex. 'PHOTO.IMG'). 4 | ; Input string in DS:SI (0x00 terminated) 5 | ; Output string in ES:DI (0x00 terminated) 6 | ; THE BUFFER SIZE SHOULD ALWAYS BE 13 BYTES, SINCE THE FILE NAME IS 12 + 0x00 7 | 8 | push ax 9 | push cx 10 | push si 11 | push di 12 | 13 | mov cx, 8 ; The name is 8 characters max 14 | .name_loop: 15 | lodsb 16 | cmp al, ' ' ; Check for space 17 | je .skip_padding_loop 18 | stosb 19 | loop .name_loop 20 | 21 | .skip_padding_loop: 22 | mov al, byte [ds:si] 23 | test al, al 24 | jz .done ; No extension 25 | cmp al, ' ' 26 | jne .extension 27 | inc si 28 | jmp .skip_padding_loop 29 | 30 | .extension: 31 | mov al, '.' 32 | stosb 33 | 34 | .extension_loop: 35 | lodsb 36 | cmp al, ' ' 37 | je .done 38 | test al, al 39 | jz .done 40 | stosb 41 | jmp .extension_loop 42 | 43 | .done: 44 | xor al, al ; Add terminator 45 | stosb 46 | 47 | pop di 48 | pop si 49 | pop cx 50 | pop ax 51 | ret 52 | -------------------------------------------------------------------------------- /kernel/internal/fat_write_entry.inc: -------------------------------------------------------------------------------- 1 | fat_write_entry: 2 | 3 | ; ************************************************************ 4 | ; Writes a new entry into the current directory buffer 5 | ; ************************************************************ 6 | 7 | ; IN: DS:SI file name 8 | ; DI = starting cluster 9 | ; AL = attributes 10 | ; BX = raw FAT time 11 | ; ECX = file size 12 | ; DX = raw FAT date 13 | 14 | ; OUT: Nothing 15 | 16 | push eax 17 | push ebx 18 | push ecx 19 | push edx 20 | push si 21 | push di 22 | push ds 23 | push es 24 | 25 | mov ax, KernelSpace 26 | mov es, ax 27 | 28 | mov word [es:.Cluster], di 29 | 30 | mov di, .ConvertedName ; Convert to fat name 31 | call string_to_fat_name 32 | 33 | mov ds, ax 34 | 35 | mov byte [.Attributes], al 36 | mov word [.RawTime], bx 37 | mov word [.RawDate], dx 38 | mov dword [.FileSize], ecx 39 | 40 | mov di, CurrentDirectoryCache 41 | mov word [.EntryCounter], 0x0000 42 | 43 | .find_empty_slot: 44 | 45 | inc word [.EntryCounter] 46 | 47 | mov ah, byte [es:di] ; Byte from the directory table, first of entry 48 | cmp ah, 0xE5 ; Empty entry? 49 | jz .write_entry 50 | 51 | mov ah, byte [es:di] ; Byte from the directory table, first of entry 52 | test ah, ah ; End of table? 53 | jz .write_entry 54 | 55 | ; Skip entry 56 | 57 | mov ax, 32 58 | mov di, CurrentDirectoryCache 59 | mul word [.EntryCounter] 60 | add di, ax 61 | jmp .find_empty_slot 62 | 63 | .write_entry: 64 | 65 | mov si, .ConvertedName 66 | 67 | mov cx, 11 ; Copy file name 68 | rep movsb 69 | 70 | mov al, byte [.Attributes] ; Store attributes 71 | stosb 72 | 73 | xor ax, ax ; Erase unused entries 74 | mov cx, 5 75 | rep stosw 76 | 77 | mov ax, word [.RawTime] ; Get time 78 | stosw 79 | 80 | mov ax, word [.RawDate] ; Get date 81 | stosw 82 | 83 | mov ax, word [.Cluster] ; Get cluster 84 | stosw 85 | 86 | mov eax, dword [.FileSize] ; Get size 87 | stosd 88 | 89 | pop es 90 | pop ds 91 | pop di 92 | pop si 93 | pop edx 94 | pop ecx 95 | pop ebx 96 | pop eax 97 | ret 98 | 99 | 100 | .EntryCounter dw 0x0000 101 | .Cluster dw 0x0000 102 | .FileSize dd 0x00000000 103 | .RawDate dw 0x0000 104 | .RawTime dw 0x0000 105 | .Attributes db 0x00 106 | .ConvertedName times 12 db 0x00 107 | -------------------------------------------------------------------------------- /kernel/internal/fat_write_root.inc: -------------------------------------------------------------------------------- 1 | fat_write_root: 2 | 3 | ; ************************************************* 4 | ; Writes the root directory (/) on the disk 5 | ; ************************************************* 6 | 7 | ; IN: DL = drive number 8 | 9 | push eax 10 | push ebx 11 | push ecx 12 | push edx 13 | 14 | push ds 15 | push es 16 | 17 | mov ax, KernelSpace 18 | mov ds, ax 19 | mov es, ax 20 | 21 | ; Fetch some metadata from the BPB 22 | 23 | mov byte [.CurrentDrive], dl 24 | 25 | mov ebx, 0x0E ; Address of the Reserved sectors constant 26 | push 0x25 27 | int 0x80 ; Load word from address 28 | 29 | mov word [.StartOfFAT], ax ; Save result 30 | 31 | mov ebx, 0x10 ; Address of the Number of FATs constant 32 | push 0x24 33 | int 0x80 ; Load word from address 34 | 35 | mov byte [.NumberOfFATs], al ; Save result 36 | 37 | mov ebx, 0x11 ; Address of the Root entries constant 38 | push 0x25 39 | int 0x80 ; Load word from address 40 | 41 | mov word [.RootEntries], ax ; Save result 42 | 43 | mov ebx, 0x16 ; Address of the Sectors per FAT constant 44 | push 0x25 45 | int 0x80 ; Load word from address 46 | 47 | mov word [.SizeOfFAT], ax ; Save result 48 | 49 | ; Calculate the start and size of the root directory 50 | 51 | ; Start = reserved_sectors + (number_of_FATs * sectors_per_FAT) 52 | ; Size = (root_entries * 32) / bytes_per_sector 53 | 54 | ; Number of fats * sector per fat in AX 55 | 56 | mov ax, word [.SizeOfFAT] 57 | mov bl, byte [.NumberOfFATs] 58 | xor bh, bh 59 | mul bx 60 | 61 | add ax, word [.StartOfFAT] ; Add reserved sectors 62 | 63 | mov word [.StartOfRoot], ax ; Save result in memory 64 | 65 | ; Root entries * 32 66 | 67 | mov ax, 32 68 | mul word [.RootEntries] 69 | 70 | xor dx, dx ; XOR DX for division 71 | div word [.BytesPerSector] 72 | 73 | mov word [.SizeOfRoot], ax ; Save result in memory 74 | 75 | ; Write root dir from buffer 76 | 77 | mov bx, CurrentDirectoryCache 78 | mov ax, word [.StartOfRoot] ; Write to here 79 | mov cx, word [.SizeOfRoot] ; Write this many sectors 80 | mov dl, byte [.CurrentDrive] ; Retrieve drive 81 | push 0x31 82 | int 0x80 83 | 84 | pop es 85 | pop ds 86 | 87 | pop edx 88 | pop ecx 89 | pop ebx 90 | pop eax 91 | 92 | ret 93 | 94 | .SizeOfFAT dw 0x0000 95 | .CurrentDrive db 0x00 96 | .StartOfFAT dw 0x0000 97 | .NumberOfFATs db 0x00 98 | .StartOfRoot dw 0x0000 99 | .SizeOfRoot dw 0x0000 100 | .RootEntries dw 0x0000 101 | .BytesPerSector dw 512 102 | -------------------------------------------------------------------------------- /kernel/internal/floppy_read_sector.inc: -------------------------------------------------------------------------------- 1 | floppy_read_sector: 2 | 3 | ; ******************************************************************** 4 | ; Reads a floppy sector with an LBA address (internal routine) 5 | ; ******************************************************************** 6 | 7 | ; IN: 8 | ; AX = LBA sector to load 9 | ; DL = Drive number 10 | ; ES = Buffer segment 11 | ; BX = Buffer offset 12 | 13 | ; OUT: 14 | ; Carry if error 15 | 16 | push ax ; Save all GPRs 17 | push bx ; Prepare entering routine 18 | push cx 19 | push dx 20 | 21 | push bx ; Save target buffer in stack 22 | push dx ; Save drive number in stack 23 | 24 | ; LBA to CHS 25 | 26 | xor dx, dx ; XOR DX for division 27 | mov bx, 18 ; Divide LBA / Sectors per track (18 on 1.44 floppy) 28 | div bx 29 | inc dl ; Adjust for sector 0 30 | mov byte [.absolute_sector], dl ; Save sector 31 | xor dx, dx ; XOR DX for division 32 | mov bx, 2 33 | div bx ; Divide / Number of heads (2) 34 | mov byte [.absolute_head], dl ; Save head 35 | mov byte [.absolute_track], al ; Save track 36 | 37 | pop dx ; Restore drive number from stack 38 | pop bx ; Restore target buffer from stack 39 | 40 | ; Prepare registers for BIOS int 0x13 41 | 42 | mov ah, 0x02 ; Read sector function 43 | mov al, 1 ; Read 1 sector 44 | mov ch, byte [.absolute_track] ; Use data we calculated 45 | mov cl, byte [.absolute_sector] 46 | mov dh, byte [.absolute_head] 47 | 48 | clc ; Clear carry for int 0x13 because some BIOSes may not clear it on success 49 | 50 | int 0x13 ; Call int 0x13 51 | 52 | .done: 53 | 54 | pop dx ; Restore all GPRs 55 | pop cx 56 | pop bx 57 | pop ax 58 | ret ; Exit routine 59 | 60 | 61 | .absolute_sector db 0x00 62 | .absolute_head db 0x00 63 | .absolute_track db 0x00 64 | -------------------------------------------------------------------------------- /kernel/internal/floppy_write_sector.inc: -------------------------------------------------------------------------------- 1 | floppy_write_sector: 2 | 3 | ; ********************************************************************* 4 | ; Writes a floppy sector with an LBA address (internal routine) 5 | ; ********************************************************************* 6 | 7 | ; IN: 8 | ; AX = LBA sector to write 9 | ; DL = Drive number 10 | ; ES = Buffer segment 11 | ; BX = Buffer offset 12 | 13 | ; OUT: 14 | ; Carry if error 15 | 16 | push ax ; Save all GPRs 17 | push bx ; Prepare entering routine 18 | push cx 19 | push dx 20 | 21 | push bx ; Save target buffer in stack 22 | push dx ; Save drive number in stack 23 | 24 | mov byte [CacheStatus], 0x00 ; Invalidate cache 25 | 26 | ; LBA to CHS 27 | 28 | xor dx, dx ; XOR DX for division 29 | mov bx, 18 ; Divide LBA / Sectors per track (18 on 1.44 floppy) 30 | div bx 31 | inc dl ; Adjust for sector 0 32 | mov byte [.absolute_sector], dl ; Save sector 33 | xor dx, dx ; XOR DX for division 34 | mov bx, 2 35 | div bx ; Divide / Number of heads (2) 36 | mov byte [.absolute_head], dl ; Save head 37 | mov byte [.absolute_track], al ; Save track 38 | 39 | pop dx ; Restore drive number from stack 40 | pop bx ; Restore target buffer from stack 41 | 42 | ; Prepare registers for BIOS int 0x13 43 | 44 | mov ah, 0x03 ; Write sector function 45 | mov al, 1 ; Write 1 sector 46 | mov ch, byte [.absolute_track] ; Use data we calculated 47 | mov cl, byte [.absolute_sector] 48 | mov dh, byte [.absolute_head] 49 | 50 | clc ; Clear carry for int 0x13 because some BIOSes may not clear it on success 51 | 52 | int 0x13 ; Call int 0x13 53 | 54 | .done: 55 | 56 | pop dx ; Restore all GPRs 57 | pop cx 58 | pop bx 59 | pop ax 60 | ret ; Exit routine 61 | 62 | 63 | .absolute_sector db 0x00 64 | .absolute_head db 0x00 65 | .absolute_track db 0x00 66 | -------------------------------------------------------------------------------- /kernel/internal/path_converter.inc: -------------------------------------------------------------------------------- 1 | path_converter: 2 | 3 | ; ***************************************************** 4 | ; Converts a relative path into an absolute one 5 | ; ***************************************************** 6 | 7 | ; IN: DS:SI = Relative path to convert 8 | ; OUT: ES:DI = Converted path 9 | 10 | push ax ; Save used registers 11 | push bx 12 | push cx 13 | push dx 14 | push si 15 | push di 16 | push gs 17 | 18 | mov ax, KernelSpace ; GS to kernel 19 | mov gs, ax 20 | 21 | mov word [gs:.TargetBuffer], di ; Save address of target location 22 | 23 | ; Check if the path is absolute 24 | 25 | lodsb 26 | cmp al, '/' 27 | je .main 28 | dec si 29 | 30 | push 0x2E ; Dump the pwd in the target buffer 31 | int 0x80 32 | 33 | push 0x2D ; Get to end of string 34 | int 0x80 35 | 36 | 37 | 38 | .main: 39 | 40 | mov bx, .DirectoryName ; Put a temporary buffer in BX to check for . or .. entries 41 | 42 | .name_loop: 43 | 44 | lodsb 45 | cmp al, '/' 46 | je .directory 47 | test al, al 48 | jz .directory 49 | mov byte [gs:bx], al 50 | inc bx 51 | jmp .name_loop 52 | 53 | .directory: 54 | 55 | mov byte [gs:bx], 0x00 ; Add terminator to buffer 56 | 57 | push si ; Save these registers 58 | push di 59 | push ds 60 | push es 61 | 62 | mov ax, KernelSpace ; Point es and ds to kernel 63 | mov ds, ax 64 | mov es, ax 65 | 66 | ; Check for reserved entries (. and ..) 67 | 68 | mov si, .DirectoryName 69 | mov di, .DotEntry 70 | 71 | push 0x08 ; Compare strings 72 | int 0x80 73 | 74 | cmp dl, 0x01 75 | je .dot_entry 76 | 77 | mov di, .DotDotEntry 78 | 79 | push 0x08 80 | int 0x80 81 | 82 | cmp dl, 0x01 83 | je .dot_dot_entry 84 | 85 | 86 | 87 | ; If not a reserved entry --- CASE 1 88 | 89 | pop es 90 | pop ds 91 | pop di 92 | pop si 93 | 94 | mov bx, .DirectoryName 95 | 96 | ; check if root dir 97 | 98 | mov ax, di 99 | dec ax 100 | cmp ax, word [gs:.TargetBuffer] 101 | je .no_slash 102 | 103 | mov al, '/' ; Add slash 104 | stosb 105 | 106 | .no_slash: 107 | 108 | .copy_to_buffer_loop: 109 | 110 | mov al, byte [gs:bx] 111 | test al, al 112 | jz .not_reserved_done 113 | inc bx 114 | stosb 115 | jmp .copy_to_buffer_loop 116 | 117 | .not_reserved_done: 118 | 119 | mov byte [es:di], 0x00 ; Put a terminator, just in case 120 | 121 | mov al, byte [ds:(si-1)] 122 | test al, al ; If end of string, done 123 | jz .done 124 | 125 | jmp .main 126 | 127 | 128 | 129 | .dot_entry: 130 | 131 | ; If a dot (.) entry --- CASE 2 132 | 133 | pop es 134 | pop ds 135 | pop di 136 | pop si 137 | 138 | mov al, byte [ds:(si-1)] 139 | test al, al ; If end of string, done 140 | jz .done 141 | 142 | jmp .main 143 | 144 | 145 | 146 | 147 | .dot_dot_entry: 148 | 149 | ; If a dot dot (..) entry --- CASE 3 150 | 151 | pop es 152 | pop ds 153 | pop di 154 | pop si 155 | 156 | .remove_last_dir_loop: 157 | 158 | ; check if root dir 159 | 160 | mov al, byte [es:di] 161 | mov byte [es:di], 0x00 162 | cmp al, '/' 163 | je .remove_dir_done 164 | 165 | mov ax, di 166 | dec ax 167 | cmp ax, word [gs:.TargetBuffer] 168 | je .remove_dir_done 169 | 170 | dec di 171 | jmp .remove_last_dir_loop 172 | 173 | .remove_dir_done: 174 | 175 | mov al, byte [ds:(si-1)] 176 | test al, al ; If end of string, done 177 | jz .done 178 | 179 | jmp .main 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | .done: 188 | 189 | pop gs 190 | pop di 191 | pop si 192 | pop dx 193 | pop cx 194 | pop bx 195 | pop ax 196 | 197 | push 0x15 ; Convert to uppercase 198 | int 0x80 199 | 200 | ret 201 | 202 | 203 | 204 | .DirectoryName times 13 db 0x00 205 | .DotEntry db '.', 0x00 206 | .DotDotEntry db '..', 0x00 207 | .TargetBuffer dw 0x0000 208 | -------------------------------------------------------------------------------- /kernel/internal/string_to_fat_name.inc: -------------------------------------------------------------------------------- 1 | string_to_fat_name: 2 | 3 | ; Trasform readable string (ex. 'photo.img') to FAT file name (ex. 'PHOTO IMG'). 4 | ; Input string in DS:SI (0x00 terminated) 5 | ; Output string in ES:DI (0x00 terminated) 6 | ; THE BUFFER SIZE SHOULD ALWAYS BE 12 BYTES, SINCE THE FILE NAME IS 11 + 0x00 7 | 8 | push ax 9 | push cx 10 | push dx 11 | push si 12 | push di 13 | 14 | push di 15 | push es 16 | 17 | mov ax, KernelSpace 18 | mov es, ax 19 | 20 | mov di, .dot_dot_entry 21 | push 0x08 22 | int 0x80 23 | 24 | cmp dl, 0x01 25 | je .ignore 26 | 27 | mov di, .dot_entry 28 | push 0x08 29 | int 0x80 30 | 31 | cmp dl, 0x01 32 | je .ignore 33 | 34 | pop es 35 | pop di 36 | 37 | mov cl, 11 38 | 39 | .clear_buffer: 40 | cmp cl, 0 41 | je .main 42 | mov al, ' ' 43 | stosb 44 | dec cl 45 | jmp .clear_buffer 46 | 47 | .main: 48 | pop di 49 | push di 50 | mov cl, 11 51 | 52 | .loop: 53 | lodsb ; Byte from SI 54 | cmp al, '.' ; Is '.'? 55 | je .pad_and_extension 56 | cmp al, 0x00 ; Is terminator? 57 | je .pad_and_convert 58 | cmp cl, 3 ; Too may characters? 59 | je .convert ; Quit 60 | stosb ; Save in DI 61 | dec cl 62 | jmp .loop 63 | 64 | .pad_and_extension: 65 | sub cl, 3 ; Sub extension size from padding 66 | .loop1: 67 | cmp cl, 0 68 | je .put_extension 69 | mov al, ' ' ; Pad with spaces 70 | dec cl 71 | stosb 72 | jmp .loop1 73 | .put_extension: 74 | mov cl, 3 75 | .loop2: 76 | cmp cl, 0 77 | je .convert 78 | lodsb ; Byte from SI 79 | cmp al, 0x00 ; Is 0x00? 80 | je .pad_and_convert 81 | stosb ; Store in DI 82 | dec cl 83 | jmp .loop2 84 | 85 | .pad_and_convert: 86 | cmp cl, 0 87 | je .convert 88 | mov al, ' ' ; Pad with spaces 89 | stosb 90 | dec cl 91 | jmp .pad_and_convert 92 | 93 | .convert: 94 | pop di ; Reset DI 95 | push di 96 | add di, 11 97 | mov byte [es:di], 0x00 ; Add 0x00 terminator 98 | sub di, 11 99 | push 0x15 100 | int 0x80 ; Lower to uppercase 101 | 102 | .done: 103 | pop di 104 | pop si 105 | pop dx 106 | pop cx 107 | pop ax 108 | ret 109 | 110 | .ignore: 111 | 112 | pop es 113 | pop di 114 | 115 | mov cx, 11 116 | 117 | .clear_buffer1: 118 | mov al, ' ' 119 | stosb 120 | loop .clear_buffer1 121 | 122 | pop di 123 | push di 124 | 125 | .copy_string: 126 | lodsb 127 | test al, al 128 | jz .done 129 | stosb 130 | jmp .copy_string 131 | 132 | .dot_dot_entry db '..', 0x00 133 | .dot_entry db '.', 0x00 134 | -------------------------------------------------------------------------------- /kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | ; ***************************************************************** 2 | ; The DankOS kernel. It contains core drivers and routines. 3 | ; ***************************************************************** 4 | 5 | org 0x0010 ; Bootloader loads us here (FFFF:0010) 6 | bits 16 ; 16-bit Real mode 7 | 8 | ; **** Bootup routines **** 9 | 10 | ; Flush registers 11 | 12 | xor eax, eax 13 | xor ebx, ebx 14 | xor ecx, ecx 15 | and edx, 0x000000FF ; (save boot drive) 16 | xor esi, esi 17 | xor edi, edi 18 | xor ebp, ebp 19 | 20 | ; Setup segments 21 | 22 | cli 23 | mov ax, KernelSpace 24 | mov ds, ax 25 | mov es, ax 26 | mov fs, ax 27 | mov gs, ax 28 | mov ss, ax 29 | mov sp, 0x7FF0 30 | 31 | push ds 32 | 33 | xor ax, ax 34 | mov ds, ax 35 | 36 | mov word [0x0200], system_call ; Enable the interrupt 0x80 for the system API 37 | mov word [0x0202], KernelSpace 38 | 39 | mov word [0x006C], break_int ; Hook the break interrupt 40 | mov word [0x006E], KernelSpace 41 | 42 | mov word [0x0070], timer_int ; Hook the timer interrupt 43 | mov word [0x0072], KernelSpace 44 | 45 | pop ds 46 | 47 | sti 48 | 49 | mov byte [BootDrive], dl ; Save boot drive 50 | 51 | push 0x29 ; Set current drive 52 | int 0x80 53 | 54 | ; Prepare the screen 55 | 56 | push 0x80 ; Enter graphics mode 57 | int 0x80 58 | 59 | push 0x82 ; Leave graphics mode (this should fix a bug on some machines) 60 | int 0x80 61 | 62 | reload: 63 | 64 | mov si, ShellName ; Use the default 'shell.bin' 65 | mov di, ShellSwitches ; No switches 66 | push 0x14 67 | int 0x80 ; Launch process #1 68 | 69 | ; Since process #1 is never supposed to quit, add an exception handler here 70 | 71 | mov si, ProcessWarning1 ; Print warning message (part 1) 72 | push 0x02 73 | int 0x80 74 | 75 | xor cl, cl 76 | xor dl, dl 77 | push 0x06 78 | int 0x80 ; Print exit code 79 | 80 | mov si, ProcessWarning2 ; Print second part of message 81 | push 0x02 82 | int 0x80 83 | 84 | push 0x18 85 | int 0x80 ; Pause 86 | 87 | mov dl, byte [BootDrive] ; Set the current drive to the boot drive 88 | push 0x29 89 | int 0x80 90 | 91 | jmp reload ; Reload shell 92 | 93 | 94 | data: 95 | 96 | ShellName db 'shell.bin', 0x00 97 | ProcessWarning1 db 0x0A, "Kernel: The root process has been terminated," 98 | db 0x0A, " process exit code: ", 0x00 99 | ProcessWarning2 db 0x0A, " The kernel will now reload 'shell.bin'." 100 | db 0x0A, "Press a key to continue...", 0x00 101 | ShellSwitches db 0x00 102 | BootDrive db 0x00 103 | 104 | ; ----- INTERNAL ROUTINES ----- 105 | 106 | %include 'kernel/internal/draw_cursor.inc' 107 | %include 'kernel/internal/clear_cursor.inc' 108 | %include 'kernel/internal/string_to_fat_name.inc' 109 | %include 'kernel/internal/erase_dir_cache.inc' 110 | %include 'kernel/internal/fat_delete_chain.inc' 111 | %include 'kernel/internal/fat_get_metadata.inc' 112 | %include 'kernel/internal/fat_load_chain.inc' 113 | %include 'kernel/internal/fat_load_root.inc' 114 | %include 'kernel/internal/fat_write_root.inc' 115 | %include 'kernel/internal/fat_name_to_string.inc' 116 | %include 'kernel/internal/fat_write_entry.inc' 117 | %include 'kernel/internal/path_converter.inc' 118 | %include 'kernel/internal/fat12_load_chain.inc' 119 | %include 'kernel/internal/fat12_delete_chain.inc' 120 | %include 'kernel/internal/floppy_read_sector.inc' 121 | %include 'kernel/internal/floppy_write_sector.inc' 122 | %include 'kernel/internal/check_bin_extension.inc' 123 | 124 | ; ----- EXTERNAL ROUTINES ----- 125 | 126 | %include 'kernel/external/beep.inc' 127 | %include 'kernel/external/stop_beep.inc' 128 | %include 'kernel/external/play_music.inc' 129 | %include 'kernel/external/stop_music.inc' 130 | %include 'kernel/external/compare_strings.inc' 131 | %include 'kernel/external/input_integer.inc' 132 | %include 'kernel/external/input_string.inc' 133 | %include 'kernel/external/lower_to_uppercase.inc' 134 | %include 'kernel/external/pause.inc' 135 | %include 'kernel/external/print_integer.inc' 136 | %include 'kernel/external/print_integer_hex.inc' 137 | %include 'kernel/external/string_copy.inc' 138 | %include 'kernel/external/string_end.inc' 139 | %include 'kernel/external/string_length.inc' 140 | %include 'kernel/external/string_to_integer.inc' 141 | %include 'kernel/external/timer_read.inc' 142 | %include 'kernel/external/upper_to_lowercase.inc' 143 | %include 'kernel/external/cut_string.inc' 144 | %include 'kernel/external/get_char.inc' 145 | %include 'kernel/external/sleep.inc' 146 | %include 'kernel/external/enter_graphics_mode.inc' 147 | %include 'kernel/external/exit_graphics_mode.inc' 148 | %include 'kernel/external/draw_pixel.inc' 149 | %include 'kernel/external/draw_line.inc' 150 | %include 'kernel/external/draw_sprite.inc' 151 | %include 'kernel/external/clear_frame_buffer.inc' 152 | %include 'kernel/external/push_frame.inc' 153 | %include 'kernel/external/get_current_palette.inc' 154 | %include 'kernel/external/print_string.inc' 155 | %include 'kernel/external/center_print_string.inc' 156 | %include 'kernel/external/initialise_screen.inc' 157 | %include 'kernel/external/set_palette.inc' 158 | %include 'kernel/external/disable_cursor.inc' 159 | %include 'kernel/external/enable_cursor.inc' 160 | %include 'kernel/external/new_line.inc' 161 | %include 'kernel/external/get_cursor_position.inc' 162 | %include 'kernel/external/set_cursor_position.inc' 163 | %include 'kernel/external/put_char.inc' 164 | %include 'kernel/external/ascii_dump.inc' 165 | %include 'kernel/external/floppy_read_sectors.inc' 166 | %include 'kernel/external/floppy_read_word.inc' 167 | %include 'kernel/external/floppy_read_byte.inc' 168 | %include 'kernel/external/floppy_read_dword.inc' 169 | %include 'kernel/external/floppy_write_sectors.inc' 170 | %include 'kernel/external/floppy_write_word.inc' 171 | %include 'kernel/external/floppy_write_byte.inc' 172 | %include 'kernel/external/floppy_write_dword.inc' 173 | %include 'kernel/external/invalid_cache.inc' 174 | %include 'kernel/external/set_current_drive.inc' 175 | %include 'kernel/external/get_current_drive.inc' 176 | %include 'kernel/external/directory_scanner.inc' 177 | %include 'kernel/external/get_current_dir.inc' 178 | %include 'kernel/external/load_dir.inc' 179 | %include 'kernel/external/load_file.inc' 180 | %include 'kernel/external/ping_file.inc' 181 | %include 'kernel/external/fat_time_to_integer.inc' 182 | %include 'kernel/external/get_version_number.inc' 183 | %include 'kernel/external/terminate_process.inc' 184 | %include 'kernel/external/start_new_program.inc' 185 | %include 'kernel/external/allocate_memory.inc' 186 | %include 'kernel/external/allocate_mem32.inc' 187 | 188 | ; ----- OTHER INCLUDES ----- 189 | 190 | %include 'kernel/other/timer_int.inc' 191 | %include 'kernel/other/break_int.inc' 192 | %include 'kernel/other/syscalls.inc' 193 | %include 'kernel/other/variables.inc' 194 | 195 | times 0x8000-($-$$) db 0x00 ; Pad reserved sectors with 0x00 196 | -------------------------------------------------------------------------------- /kernel/other/break_int.inc: -------------------------------------------------------------------------------- 1 | break_int: 2 | 3 | push si 4 | push ds 5 | 6 | mov si, KernelSpace 7 | mov ds, si 8 | 9 | mov si, .msg 10 | push 0x02 11 | int 0x80 12 | 13 | mov byte [BreakFlag], 0x01 14 | 15 | pop ds 16 | pop si 17 | 18 | iret 19 | 20 | .msg db 0x0A, 'Kernel: Aborting execution via CTRL+Break.', 0x0A, 0x00 21 | -------------------------------------------------------------------------------- /kernel/other/syscalls.inc: -------------------------------------------------------------------------------- 1 | system_call: 2 | 3 | ; ** int 0x80 has been called ** 4 | 5 | ; ** check for break flag ** 6 | 7 | push ax 8 | push gs 9 | 10 | mov ax, KernelSpace 11 | mov gs, ax 12 | 13 | cmp byte [gs:BreakFlag], 0x01 14 | 15 | pop gs 16 | pop ax 17 | 18 | je .break_execution 19 | 20 | ; CURRENT STACK: function number|flags|return offset|return segment 21 | 22 | push bp 23 | 24 | ; CURRENT STACK: function number|flags|return offset|return segment|bp 25 | 26 | mov bp, sp 27 | add bp, 8 28 | push ax 29 | 30 | ; CURRENT STACK: function number|flags|return offset|return segment|bp|ax 31 | 32 | push bx 33 | 34 | ; CURRENT STACK: function number|flags|return offset|return segment|bp|ax|bx 35 | 36 | mov ax, word [ss:bp] 37 | sub bp, 2 38 | mov bx, word [ss:bp] 39 | add bp, 2 40 | mov word [ss:bp], bx 41 | 42 | ; CURRENT STACK: flags|flags|return offset|return segment|bp|ax|bx 43 | 44 | sub bp, 4 45 | mov bx, word [ss:bp] 46 | add bp, 2 47 | mov word [ss:bp], bx 48 | 49 | ; CURRENT STACK: flags|return offset|return offset|return segment|bp|ax|bx 50 | 51 | sub bp, 4 52 | mov bx, word [ss:bp] 53 | add bp, 2 54 | mov word [ss:bp], bx 55 | 56 | ; CURRENT STACK: flags|return offset|return segment|return segment|bp|ax|bx 57 | 58 | sub bp, 2 59 | mov word [ss:bp], ax 60 | 61 | ; CURRENT STACK: flags|return offset|return segment|function number|bp|ax|bx 62 | 63 | pop bx 64 | pop ax 65 | pop bp 66 | 67 | ; TARGET STACK: flags|return offset|return segment|function number 68 | 69 | add sp, 2 70 | 71 | ; ** Function list ** 72 | 73 | xchg sp, bp 74 | cmp word [ss:(bp-2)], 0x00 75 | xchg sp, bp 76 | je terminate_process 77 | 78 | xchg sp, bp 79 | cmp word [ss:(bp-2)], 0x01 80 | xchg sp, bp 81 | je put_char 82 | 83 | xchg sp, bp 84 | cmp word [ss:(bp-2)], 0x02 85 | xchg sp, bp 86 | je print_string 87 | 88 | xchg sp, bp 89 | cmp word [ss:(bp-2)], 0x03 90 | xchg sp, bp 91 | je new_line 92 | 93 | xchg sp, bp 94 | cmp word [ss:(bp-2)], 0x04 95 | xchg sp, bp 96 | je string_to_integer 97 | 98 | xchg sp, bp 99 | cmp word [ss:(bp-2)], 0x05 100 | xchg sp, bp 101 | je print_integer_hex 102 | 103 | xchg sp, bp 104 | cmp word [ss:(bp-2)], 0x06 105 | xchg sp, bp 106 | je print_integer 107 | 108 | xchg sp, bp 109 | cmp word [ss:(bp-2)], 0x07 110 | xchg sp, bp 111 | je input_integer 112 | 113 | xchg sp, bp 114 | cmp word [ss:(bp-2)], 0x08 115 | xchg sp, bp 116 | je compare_strings 117 | 118 | xchg sp, bp 119 | cmp word [ss:(bp-2)], 0x09 120 | xchg sp, bp 121 | je string_length 122 | 123 | xchg sp, bp 124 | cmp word [ss:(bp-2)], 0x0A 125 | xchg sp, bp 126 | je initialise_screen 127 | 128 | xchg sp, bp 129 | cmp word [ss:(bp-2)], 0x0B 130 | xchg sp, bp 131 | je disable_cursor 132 | 133 | xchg sp, bp 134 | cmp word [ss:(bp-2)], 0x0C 135 | xchg sp, bp 136 | je enable_cursor 137 | 138 | xchg sp, bp 139 | cmp word [ss:(bp-2)], 0x0D 140 | xchg sp, bp 141 | je get_cursor_position 142 | 143 | xchg sp, bp 144 | cmp word [ss:(bp-2)], 0x0E 145 | xchg sp, bp 146 | je set_cursor_position 147 | 148 | xchg sp, bp 149 | cmp word [ss:(bp-2)], 0x0F 150 | xchg sp, bp 151 | je center_print_string 152 | 153 | xchg sp, bp 154 | cmp word [ss:(bp-2)], 0x10 155 | xchg sp, bp 156 | je input_string 157 | 158 | xchg sp, bp 159 | cmp word [ss:(bp-2)], 0x11 160 | xchg sp, bp 161 | je set_palette 162 | 163 | xchg sp, bp 164 | cmp word [ss:(bp-2)], 0x12 165 | xchg sp, bp 166 | je load_file 167 | 168 | xchg sp, bp 169 | cmp word [ss:(bp-2)], 0x13 170 | xchg sp, bp 171 | je get_current_drive 172 | 173 | xchg sp, bp 174 | cmp word [ss:(bp-2)], 0x14 175 | xchg sp, bp 176 | je start_new_program 177 | 178 | xchg sp, bp 179 | cmp word [ss:(bp-2)], 0x15 180 | xchg sp, bp 181 | je lower_to_uppercase 182 | 183 | xchg sp, bp 184 | cmp word [ss:(bp-2)], 0x16 185 | xchg sp, bp 186 | je upper_to_lowercase 187 | 188 | xchg sp, bp 189 | cmp word [ss:(bp-2)], 0x17 190 | xchg sp, bp 191 | je get_current_palette 192 | 193 | xchg sp, bp 194 | cmp word [ss:(bp-2)], 0x18 195 | xchg sp, bp 196 | je pause 197 | 198 | xchg sp, bp 199 | cmp word [ss:(bp-2)], 0x19 200 | xchg sp, bp 201 | je allocate_memory 202 | 203 | xchg sp, bp 204 | cmp word [ss:(bp-2)], 0x1A 205 | xchg sp, bp 206 | je cut_string 207 | 208 | xchg sp, bp 209 | cmp word [ss:(bp-2)], 0x1B 210 | xchg sp, bp 211 | je ascii_dump 212 | 213 | xchg sp, bp 214 | cmp word [ss:(bp-2)], 0x1C 215 | xchg sp, bp 216 | je get_char 217 | 218 | xchg sp, bp 219 | cmp word [ss:(bp-2)], 0x1D 220 | xchg sp, bp 221 | je sleep 222 | 223 | xchg sp, bp 224 | cmp word [ss:(bp-2)], 0x1E 225 | xchg sp, bp 226 | je stop_beep 227 | 228 | xchg sp, bp 229 | cmp word [ss:(bp-2)], 0x1F 230 | xchg sp, bp 231 | je play_music 232 | 233 | xchg sp, bp 234 | cmp word [ss:(bp-2)], 0x20 235 | xchg sp, bp 236 | je timer_read 237 | 238 | xchg sp, bp 239 | cmp word [ss:(bp-2)], 0x21 240 | xchg sp, bp 241 | je load_dir 242 | 243 | xchg sp, bp 244 | cmp word [ss:(bp-2)], 0x22 245 | xchg sp, bp 246 | je beep 247 | 248 | xchg sp, bp 249 | cmp word [ss:(bp-2)], 0x23 250 | xchg sp, bp 251 | je floppy_read_sectors 252 | 253 | xchg sp, bp 254 | cmp word [ss:(bp-2)], 0x24 255 | xchg sp, bp 256 | je floppy_read_byte 257 | 258 | xchg sp, bp 259 | cmp word [ss:(bp-2)], 0x25 260 | xchg sp, bp 261 | je floppy_read_word 262 | 263 | xchg sp, bp 264 | cmp word [ss:(bp-2)], 0x26 265 | xchg sp, bp 266 | je floppy_read_dword 267 | 268 | xchg sp, bp 269 | cmp word [ss:(bp-2)], 0x27 270 | xchg sp, bp 271 | je string_copy 272 | 273 | xchg sp, bp 274 | cmp word [ss:(bp-2)], 0x28 275 | xchg sp, bp 276 | je directory_scanner 277 | 278 | xchg sp, bp 279 | cmp word [ss:(bp-2)], 0x29 280 | xchg sp, bp 281 | je set_current_drive 282 | 283 | xchg sp, bp 284 | cmp word [ss:(bp-2)], 0x2A 285 | xchg sp, bp 286 | je stop_music 287 | 288 | 289 | 290 | 291 | 292 | 293 | xchg sp, bp 294 | cmp word [ss:(bp-2)], 0x2B 295 | xchg sp, bp 296 | je ping_file 297 | 298 | 299 | 300 | 301 | 302 | 303 | xchg sp, bp 304 | cmp word [ss:(bp-2)], 0x2C 305 | xchg sp, bp 306 | je fat_time_to_integer 307 | 308 | xchg sp, bp 309 | cmp word [ss:(bp-2)], 0x2D 310 | xchg sp, bp 311 | je string_end 312 | 313 | xchg sp, bp 314 | cmp word [ss:(bp-2)], 0x2E 315 | xchg sp, bp 316 | je get_current_dir 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | xchg sp, bp 327 | cmp word [ss:(bp-2)], 0x31 328 | xchg sp, bp 329 | je floppy_write_sectors 330 | 331 | xchg sp, bp 332 | cmp word [ss:(bp-2)], 0x32 333 | xchg sp, bp 334 | je floppy_write_byte 335 | 336 | xchg sp, bp 337 | cmp word [ss:(bp-2)], 0x33 338 | xchg sp, bp 339 | je floppy_write_word 340 | 341 | xchg sp, bp 342 | cmp word [ss:(bp-2)], 0x34 343 | xchg sp, bp 344 | je floppy_write_dword 345 | 346 | xchg sp, bp 347 | cmp word [ss:(bp-2)], 0x35 348 | xchg sp, bp 349 | je invalid_cache 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | xchg sp, bp 360 | cmp word [ss:(bp-2)], 0x80 361 | xchg sp, bp 362 | je enter_graphics_mode 363 | 364 | xchg sp, bp 365 | cmp word [ss:(bp-2)], 0x81 366 | xchg sp, bp 367 | je draw_pixel 368 | 369 | xchg sp, bp 370 | cmp word [ss:(bp-2)], 0x82 371 | xchg sp, bp 372 | je exit_graphics_mode 373 | 374 | xchg sp, bp 375 | cmp word [ss:(bp-2)], 0x83 376 | xchg sp, bp 377 | je draw_line 378 | 379 | xchg sp, bp 380 | cmp word [ss:(bp-2)], 0x84 381 | xchg sp, bp 382 | je draw_sprite 383 | 384 | xchg sp, bp 385 | cmp word [ss:(bp-2)], 0x85 386 | xchg sp, bp 387 | je clear_frame_buffer 388 | 389 | xchg sp, bp 390 | cmp word [ss:(bp-2)], 0x86 391 | xchg sp, bp 392 | je push_frame 393 | 394 | xchg sp, bp 395 | cmp word [ss:(bp-2)], 0x87 396 | xchg sp, bp 397 | je get_version_number 398 | 399 | 400 | 401 | ; 32-bit calls 402 | 403 | xchg sp, bp 404 | cmp word [ss:(bp-2)], 0xA0 405 | xchg sp, bp 406 | je allocate_mem32 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | ; *** Invalid system call exception handler 416 | 417 | mov ax, KernelSpace 418 | mov ds, ax 419 | mov si, .invalid_call_msg 420 | push 0x02 421 | int 0x80 422 | push 0x00 423 | int 0x80 424 | 425 | 426 | .invalid_call_msg db 0x0A, "Kernel: An invalid system call has been issued by the program." 427 | db 0x0A, " Execution aborted.", 0x0A, 0x00 428 | 429 | .break_execution: 430 | 431 | mov ax, KernelSpace 432 | mov ds, ax 433 | mov byte [BreakFlag], 0x00 434 | mov eax, 0xFFFFFFFE 435 | push 0x00 436 | int 0x80 437 | -------------------------------------------------------------------------------- /kernel/other/timer_int.inc: -------------------------------------------------------------------------------- 1 | ; *********************************************** 2 | ; Executes timer-related kernel functions 3 | ; *********************************************** 4 | 5 | timer_int: 6 | 7 | push eax 8 | push gs 9 | 10 | mov ax, KernelSpace 11 | mov gs, ax 12 | 13 | inc dword [gs:ClockTicks] 14 | 15 | cmp byte [gs:MusicPlayingFlag], 0x01 16 | je .playmusic 17 | 18 | 19 | 20 | 21 | 22 | 23 | .done: 24 | 25 | pop gs 26 | pop eax 27 | 28 | iret 29 | 30 | 31 | 32 | .playmusic: 33 | 34 | push cx 35 | push esi 36 | push ds 37 | 38 | mov cx, word [gs:MusicSegment] 39 | mov ds, cx 40 | 41 | mov esi, dword [gs:MusicCurrentNote] 42 | 43 | xor cx, cx 44 | mov cl, byte [ds:esi] 45 | 46 | test cl, cl 47 | jz .music_end 48 | 49 | cmp byte [gs:NoteLengthCounter], cl 50 | je .next_note 51 | 52 | inc byte [gs:NoteLengthCounter] 53 | 54 | .playmusic_done: 55 | 56 | pop ds 57 | pop esi 58 | pop cx 59 | jmp .done 60 | 61 | 62 | .next_note: 63 | 64 | add dword [gs:MusicCurrentNote], 3 65 | mov byte [gs:NoteLengthCounter], 0 66 | 67 | mov esi, dword [gs:MusicCurrentNote] 68 | 69 | mov cx, word [ds:esi+1] 70 | test cx, cx 71 | jz .music_pause 72 | 73 | push 0x22 74 | int 0x80 75 | 76 | jmp .playmusic_done 77 | 78 | 79 | .music_end: 80 | 81 | push 0x1E 82 | int 0x80 83 | 84 | mov byte [gs:MusicPlayingFlag], 0x00 85 | mov byte [gs:NoteLengthCounter], 0 86 | jmp .playmusic_done 87 | 88 | 89 | .music_pause: 90 | 91 | push 0x1E 92 | int 0x80 93 | 94 | jmp .playmusic_done 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /kernel/other/variables.inc: -------------------------------------------------------------------------------- 1 | ; ********************************************************** 2 | ; This file contains all the global Kernel variables 3 | ; ********************************************************** 4 | 5 | ; VERSION NUMBER - CHANGE THIS EACH RELEASE 6 | 7 | Version db '0.0.0.20-alpha', 0x00 8 | 9 | ; File system 10 | 11 | CurrentDrive db 0x00 12 | CurrentDirectoryCache equ 0xC000 13 | CurrentDirectoryPath times 129 db 0x00 14 | CurrentDirectoryCluster dw 0x0000 15 | 16 | ; Video 17 | 18 | CursorLocation dw 0x0000 19 | CharAttributes db 0x07 20 | CursorAttributes db 0x70 21 | CursorStatus db 0x01 22 | 23 | ; Kernel 24 | 25 | KernelSpace equ 0xFFFF 26 | TopSegment dw 0x0050 27 | TopMemory dd 0x00500000 28 | StackPointer dd 0x00000000 29 | StackSegment dw 0x0000 30 | FrameBuffer equ 0x00110000 31 | ClockTicks dd 0x00000000 32 | BreakFlag db 0x00 33 | 34 | ; Music 35 | 36 | MusicPlayingFlag db 0x00 37 | MusicRepeatFlag db 0x00 38 | MusicStartAddress dd 0x00000000 39 | MusicCurrentNote dd 0x00000000 40 | NoteLengthCounter db 0x00 41 | MusicSegment dw 0x0000 42 | 43 | ; Disk 44 | 45 | CacheStatus db 0x00 46 | DriveInCache db 0x00 47 | SectorInCache dw 0x0000 48 | DiskCache times 512 db 0x00 49 | -------------------------------------------------------------------------------- /make_me.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | printf "== DankOS autobuild tool ==\n\n" 4 | 5 | if [[ $EUID -ne 0 ]]; then 6 | printf "This script requires root privileges. Run with 'sudo' or as root.\n" 7 | exit 1 8 | fi 9 | 10 | # Backup data to a "dankos.old" file. 11 | printf "All data previously stored in 'dankos.img' will be lost (if it exists)!\n" 12 | printf "A 'dankos.old' backup will be made as a failsafe.\n" 13 | rm dankos.old 2> /dev/null 14 | mv dankos.img dankos.old 2> /dev/null 15 | 16 | printf "Assembling bootloader...\n" 17 | nasm bootloader/bootloader.asm -f bin -o dankos.img 18 | 19 | printf "Assembling kernel...\n" 20 | nasm kernel/kernel.asm -f bin -o kernel.bin 21 | 22 | printf "Installing kernel...\n" 23 | cat kernel.bin >> dankos.img 24 | rm kernel.bin 25 | 26 | # Create a image for DankOS to be stored in 27 | printf "Expanding image...\n" 28 | dd bs=512 count=2812 if=/dev/zero >> dankos.img 2> /dev/null 29 | 30 | printf "Creating temporary folder to store binaries...\n" 31 | mkdir tmp 32 | 33 | printf "Assembling content of the assembly sources in the 'sources' directory...\n" 34 | for asm_file in sources/*.asm 35 | do 36 | base_name=${asm_file%.asm} 37 | base_name=${base_name:8} 38 | printf "Assembling '$asm_file'...\n" 39 | nasm "$asm_file" -f bin -o "tmp/${base_name}.bin" 40 | done 41 | 42 | printf "Creating mount point for image...\n" 43 | mkdir mnt 44 | 45 | printf "Mounting image...\n" 46 | 47 | if [[ "`uname`" == "Linux" ]]; then 48 | mount dankos.img ./mnt 49 | fi 50 | 51 | if [[ "`uname`" == "FreeBSD" ]]; then 52 | mdconfig -a -t vnode -f dankos.img -u 0 53 | mount_msdosfs /dev/md0 ./mnt 54 | fi 55 | 56 | printf "Copying files to image...\n" 57 | cp -r extra/* mnt/ 2> /dev/null 58 | cp tmp/* mnt/ 59 | cp LICENSE.md mnt/license.txt 60 | 61 | printf "Unmounting image...\n" 62 | sync 63 | umount ./mnt 64 | 65 | if [[ `uname` == "FreeBSD" ]]; then 66 | mdconfig -du md0 67 | fi 68 | 69 | printf "Cleaning up...\n" 70 | rm -rf tmp 71 | rm -rf mnt 72 | 73 | printf "Done!\n\n" 74 | printf "If everything executed correctly, a file named 'dankos.img'\n" 75 | printf "containing the contents of the 'extra' folder and the binaries assembled\n" 76 | printf "from the 'sources' folder should have been built.\n" 77 | 78 | exit 0 79 | -------------------------------------------------------------------------------- /sources/beep.asm: -------------------------------------------------------------------------------- 1 | org 0x100 2 | bits 16 3 | 4 | %include 'includes/music.inc' 5 | 6 | mov esi, music 7 | push 0x1F 8 | int 0x80 9 | 10 | mov esi, msg 11 | push 0x02 12 | int 0x80 13 | 14 | push 0x03 15 | int 0x80 16 | 17 | push 0x18 18 | int 0x80 19 | 20 | push 0x2A 21 | int 0x80 22 | 23 | push 0x00 ; Return 24 | int 0x80 25 | 26 | 27 | msg db "press a key to stop playing", 0x00 28 | 29 | music: 30 | 31 | ; idk some music 32 | 33 | 34 | db 5 35 | dw C_oct_below 36 | 37 | db 5 38 | dw D_oct_below 39 | 40 | db 5 41 | dw E_oct_below 42 | 43 | db 5 44 | dw F_oct_below 45 | 46 | db 5 47 | dw G_oct_below 48 | 49 | db 5 50 | dw A 51 | 52 | db 5 53 | dw B 54 | 55 | db 5 56 | dw C 57 | 58 | db 5 59 | dw B 60 | 61 | db 5 62 | dw A 63 | 64 | db 5 65 | dw G_oct_below 66 | 67 | db 5 68 | dw F_oct_below 69 | 70 | db 5 71 | dw E_oct_below 72 | 73 | db 5 74 | dw D_oct_below 75 | 76 | db 20 77 | dw C_oct_below 78 | 79 | db 0 80 | -------------------------------------------------------------------------------- /sources/shell.asm: -------------------------------------------------------------------------------- 1 | ; ** DankOS shell ** 2 | 3 | org 0x0100 4 | 5 | bits 16 ; 16-bit real mode 6 | 7 | mov ax, 0xFFFF ; Reserve a 64kb segment of memory for file operations 8 | push 0x19 9 | int 0x80 10 | mov word [FileBuffer], cx ; Save segment 11 | 12 | mov si, intro ; Print intro 13 | push 0x02 14 | int 0x80 15 | 16 | prompt_loop: 17 | 18 | mov al, '[' ; Draw prompt 19 | push 0x01 20 | int 0x80 21 | push 0x13 ; Get current drive 22 | int 0x80 23 | xor eax, eax 24 | mov al, dl 25 | xor cl, cl 26 | xor dl, dl 27 | push 0x06 ; Print drive number 28 | int 0x80 29 | mov al, ']' ; Close bracket 30 | push 0x01 31 | int 0x80 32 | 33 | mov di, CurrentDir 34 | push 0x2E ; Get current dir 35 | int 0x80 36 | mov si, CurrentDir 37 | push 0x02 ; Print current dir 38 | int 0x80 39 | 40 | mov si, prompt ; Draw prompt 41 | push 0x02 42 | int 0x80 43 | mov bx, 0xFF ; Limit input to 0xFF characters 44 | mov di, prompt_input ; Point to local buffer 45 | push 0x10 46 | int 0x80 ; Input string 47 | push 0x03 48 | int 0x80 ; New line 49 | cmp byte [prompt_input], 0x00 ; If no input, restart loop 50 | je prompt_loop 51 | 52 | ; *** Extract command line switches from the input *** 53 | 54 | extract_switches: 55 | 56 | mov si, prompt_input ; Setup destination and source indexes 57 | mov di, command_line_switches 58 | 59 | .find_space_loop: 60 | lodsb ; Byte from SI 61 | cmp al, ' ' ; Is it space? 62 | je .get_switches ; If it is, save switches 63 | test al, al ; Is it 0x00? 64 | jz .no_switches ; If it is, write a 0x00 in the buffer, and quit 65 | jmp .find_space_loop ; Otherwise loop 66 | 67 | .get_switches: 68 | mov byte [si-1], 0x00 ; Add a terminator to the input 69 | push 0x27 70 | int 0x80 71 | jmp .done 72 | 73 | .no_switches: 74 | mov byte [di], 0x00 75 | 76 | .done: 77 | 78 | ; ***** Check for internal commands ***** 79 | 80 | mov si, prompt_input 81 | 82 | mov di, exit_msg ; Exit command 83 | push 0x08 84 | int 0x80 85 | cmp dl, 0x01 86 | je exit_cmd 87 | 88 | mov di, clear_msg ; Clear command 89 | push 0x08 90 | int 0x80 91 | cmp dl, 0x01 92 | je clear_cmd 93 | 94 | mov di, help_msg ; Help command 95 | push 0x08 96 | int 0x80 97 | cmp dl, 0x01 98 | je help_cmd 99 | 100 | mov di, ls_msg ; Ls command 101 | push 0x08 102 | int 0x80 103 | cmp dl, 0x01 104 | je ls_cmd 105 | 106 | mov di, dir_msg ; Dir (alias) command 107 | push 0x08 108 | int 0x80 109 | cmp dl, 0x01 110 | je ls_cmd 111 | 112 | mov di, cat_msg ; Cat command 113 | push 0x08 114 | int 0x80 115 | cmp dl, 0x01 116 | je cat_cmd 117 | 118 | mov di, cd_msg ; Cd command 119 | push 0x08 120 | int 0x80 121 | cmp dl, 0x01 122 | je cd_cmd 123 | 124 | mov di, time_msg ; Time command 125 | push 0x08 126 | int 0x80 127 | cmp dl, 0x01 128 | je time_cmd 129 | 130 | mov di, debug_msg ; Debug command 131 | push 0x08 132 | int 0x80 133 | cmp dl, 0x01 134 | je debug_cmd 135 | 136 | mov di, image_msg ; Image command 137 | push 0x08 138 | int 0x80 139 | cmp dl, 0x01 140 | je image_cmd 141 | 142 | mov di, ver_msg ; Ver command 143 | push 0x08 144 | int 0x80 145 | cmp dl, 0x01 146 | je ver_cmd 147 | 148 | mov di, colour_msg ; Colour command 149 | push 0x08 150 | int 0x80 151 | cmp dl, 0x01 152 | je colour_cmd 153 | 154 | mov di, color_msg ; Color (alias) command 155 | push 0x08 156 | int 0x80 157 | cmp dl, 0x01 158 | je colour_cmd 159 | 160 | mov di, root_msg ; Root command 161 | push 0x08 162 | int 0x80 163 | cmp dl, 0x01 164 | je root_cmd 165 | 166 | 167 | 168 | 169 | 170 | mov si, prompt_input ; Prepare SI for start process function 171 | mov di, command_line_switches ; Prepare to pass the switches 172 | push 0x14 173 | int 0x80 ; Try to start new process 174 | 175 | cmp eax, 0xFFFFFFFF ; If fail, add .bin and try again 176 | jne prompt_loop ; Otherwise restart the loop 177 | 178 | 179 | ; Try to add a .bin and load the file again 180 | 181 | add_bin: 182 | 183 | push 0x09 184 | int 0x80 185 | cmp cx, 12 186 | jg invalid_command 187 | 188 | mov di, bin_added_buffer 189 | 190 | push 0x27 191 | int 0x80 192 | 193 | mov si, bin_added_buffer 194 | .loop: 195 | mov al, byte [ds:si] 196 | test al, al 197 | jz .add_bin 198 | inc si 199 | jmp .loop 200 | 201 | .add_bin: 202 | mov di, si 203 | mov si, bin_msg 204 | push 0x27 205 | int 0x80 206 | 207 | ; Try to load again 208 | 209 | mov si, bin_added_buffer ; Prepare SI for start process function 210 | mov di, command_line_switches ; Prepare to pass the switches 211 | push 0x14 212 | int 0x80 ; Try to start new process 213 | cmp eax, 0xFFFFFFFF ; If fail, print error message 214 | jne prompt_loop ; Otherwise restart the loop 215 | 216 | invalid_command: 217 | 218 | mov si, not_found 219 | push 0x02 220 | int 0x80 221 | jmp prompt_loop 222 | 223 | data: 224 | 225 | intro db 0x0A, "DankOS shell, welcome!", 0x0A 226 | db 0x0A, "Type 'help' to get started.", 0x0A 227 | db 0x0A, 0x00 228 | 229 | prompt db '# ', 0x00 230 | 231 | not_found db 'Invalid command or file name.', 0x0A, 0x00 232 | 233 | prompt_input times 0x100 db 0x00 234 | 235 | bin_added_buffer times 13 db 0x00 236 | 237 | command_line_switches times 0x100 db 0x00 238 | 239 | bin_msg db '.bin', 0x00 240 | 241 | CurrentDir times 130 db 0x00 242 | 243 | FileBuffer dw 0x0000 244 | 245 | 246 | internal_commands: 247 | 248 | exit_msg db 'exit', 0x00 249 | clear_msg db 'clear', 0x00 250 | help_msg db 'help', 0x00 251 | ls_msg db 'ls', 0x00 252 | cat_msg db 'cat', 0x00 253 | cd_msg db 'cd', 0x00 254 | time_msg db 'time', 0x00 255 | debug_msg db 'debug', 0x00 256 | image_msg db 'image', 0x00 257 | ver_msg db 'ver', 0x00 258 | dir_msg db 'dir', 0x00 259 | colour_msg db 'colour', 0x00 260 | color_msg db 'color', 0x00 261 | root_msg db 'root', 0x00 262 | 263 | 264 | 265 | 266 | %include 'includes/shell/exit.inc' 267 | %include 'includes/shell/clear.inc' 268 | %include 'includes/shell/help.inc' 269 | %include 'includes/shell/ls.inc' 270 | %include 'includes/shell/cat.inc' 271 | %include 'includes/shell/cd.inc' 272 | %include 'includes/shell/time.inc' 273 | %include 'includes/shell/debug.inc' 274 | %include 'includes/shell/image.inc' 275 | %include 'includes/shell/ver.inc' 276 | %include 'includes/shell/colour.inc' 277 | %include 'includes/shell/root.inc' 278 | --------------------------------------------------------------------------------