bpBytesPerSector equ 0x0b bpSectorsPerCluster equ 0x0d bpReservedSectors equ 0x0e bpNoFATs equ 0x10 bpRootDirEntries equ 0x11 bpLVSectors equ 0x13 bpMediumID equ 0x15 bpSectorsPerFat equ 0x16 bpSectorsPerTrack equ 0x18 bpHeads equ 0x1a bpHiddenSectors equ 0x1c bpDriveNo equ 0x24 bpSignature equ 0x26 [BITS 16] ; Update the IVT with our interrupt handler mov bx, 0 mov ds, bx mov word [ds:136], ihdlr mov word [ds:138], cs mov ax, 2000h mov ds, ax mov ax, 7c0h mov fs, ax ; Set up kernel specifics ; Root Directory Entries will be at 2000h:2000h ; FAT1 will be at 2000h:4000h ; Load sectors RDE to 2000h:2000h mov ax, 2000h mov es, ax mov bx, 2000h ; Calculate position of RDE mov ax, word [fs:bpSectorsPerFat] movzx cx, byte [fs:bpNoFATs] mul cx add ax, 2 call prep_i13 mov al, 16 int 13h ; Load sectors 2 through 36 to 2000h:4000h mov ax, 2000h mov es, ax mov bx, 4000h mov ax, 2 call prep_i13 mov ax, word [fs:bpSectorsPerFat] mov ah, 2 int 13h ; Calculate file offset mov ax, word [fs:bpSectorsPerFat] movzx cx, byte [fs:bpNoFATs] mul cx push ax mov ax, word [fs:bpRootDirEntries] mov cx, 16 div cx mov bx, ax pop ax add ax, bx mov word [fileoffset], ax push msg call print cmd_loop: push cmd_prompt call print ; Clear command buffer mov al, 0 mov di, user_cmd mov cx, 64 clear_loop: stosb loop clear_loop push user_cmd push 64 call readline push newline call print mov si, user_cmd mov di, cmd_help_text mov cx, 4 rep cmpsb je cmd_help mov si, user_cmd mov di, cmd_clear_text mov cx, 5 rep cmpsb je cmd_clear ; If the user hasn't run a command we should determine if they're trying to run a program. ; Decode input to filename push user_cmd call decode_filename ; Search for file mov si, ax call file_exists ; If it doesn't exist jump to error cmp ax, 0 je handle_error ; Define the segment where we will load our programs program_segment equ 4000h ; If the file exists load it at program_segment:0 push ax push 0 push program_segment call load_file ; Let programs know what segment they're loaded at push program_segment ; Make a call to program_segment:0 call program_segment:0 ; We've now returned. ; Clean up pushed segment pop ax ; Recover ds mov ax, 2000h mov ds, ax mov es, ax ; jmp $ ; Loop jmp cmd_loop handle_error: push cmd_err call print jmp cmd_loop cmd_help: push cmd_help_msg call print jmp cmd_loop cmd_help_msg: db "XnoeOS Help Dialogue", 13, 10 db "--------------------", 13, 10 db "Commands: ", 13, 10 db " - help", 13, 10 db " : Displays this message", 13, 10 db " - clear", 13, 10 db " : Clears the screen", 13, 10 db 0 cmd_clear: mov ah, 02h mov dh, 0 mov dl, 0 int 10h mov ah, 0ah mov cx, 2000 mov al, 20h int 10h jmp cmd_loop data: msg db "Kernel OK!", 13, 10, 0 cmd_prompt db ">>> ", 0 cmd_err db "Bad Command or filename!", 13, 10, 13, 10, 0 cmd_help_text db "HELP" cmd_clear_text db "CLEAR" newline db 13, 10, 0 program_two db "HELLO BIN" user_cmd: times 64 db 0 ; print(str) print: push bp mov bp, sp mov si, [bp + 4] mov ah, 0eh mov cx, 1 mov bh, 0 print_loop: lodsb cmp al, 0 je print_exit ; Use Unix Line endings (\n) cmp al, 10 jne _print_skip int 10h mov al, 13 int 10h _print_skip: int 10h jmp print_loop print_exit: pop bp ret 2 ; readline(max length, buffer) readline: push bp mov bp, sp mov di, [bp + 6] mov bx, 0 readline_loop: mov ah, 0h int 16h cmp ah, 01ch je readline_exit cmp ah, 0eh je readline_backspace ; Process all user input as upper case cmp al, 0x61 jl not_lower cmp al, 0x79 jg not_lower and al, 223 not_lower: mov byte [di], al inc di inc bx mov ah, 0eh mov cx, 1 int 10h mov ax, [bp + 4] cmp bx, ax je readline_exit jmp readline_loop readline_backspace: cmp bx, 0 je readline_loop dec di dec bx mov ah, 0eh mov cx, 1 int 10h mov ah, 0ah mov cx, 1 mov al, 20h int 10h jmp readline_loop readline_exit: pop bp ret 4 file_exists: push si mov bp, sp mov cx, 256 ; Hardcode the amount of entries for now mov ax, 2000h mov es, ax xor ax, ax file_exists_loop: pop si ; Get value in to si push si ; Keep track of original value xchg cx, dx mov di, 2000h ; Root Entries is at 2000h:2000h add di, ax mov cx, 11 rep cmpsb je file_exists_found add ax, 32 xchg cx, dx loop file_exists_loop file_exists_not_found: mov ax, 0 pop si ret file_exists_found: mov ax, [es:di+0fh] pop si ret ; loadfile(segment, offset, initsector) load_file: push bp mov bp, sp push ds push fs mov ax, 7c0h mov fs, ax mov ax, 2000h mov ds, ax mov ax, word [bp + 4] mov es, ax load_file_loop: mov bx, word [bp + 6] movzx ax, byte [bp + 8] add ax, word [fileoffset] call prep_i13 int 13h add word [bp + 6], 512 mov si, word [bp + 8] shl si, 1 add si, 4000h ; add si, 1 cmp word [ds:si], 0ffffh je load_file_loaded add word [bp + 8], 1 jmp load_file_loop load_file_loaded: pop fs pop ds pop bp ret 6 decode_filename: push bp mov bp, sp push word [bp + 4] ; First we want to clear the buffer with 0x20s mov al, 20h mov cx, 11 mov di, _decode_buffer decode_clear_loop: stosb loop decode_clear_loop pop si mov cx, 8 mov bx, 0 decode_filename_loop: lodsb cmp al, "." je decode_filename_stage2 mov byte [_decode_buffer+bx], al inc bx loop decode_filename_loop decode_filename_stage2: mov bx, 8 mov cx, 3 decode_filename_stage2_loop: lodsb cmp al, 0 je decode_filename_final mov byte [_decode_buffer+bx], al inc bx loop decode_filename_stage2_loop decode_filename_final: pop bp mov ax, _decode_buffer ret 2 _decode_buffer: times 11 db 0 ihdlr: cmp ah, 01h jne _ihdlr_2 push si call print jmp _ihdlr_fin _ihdlr_2: cmp ah, 02h jne _ihdlr_3 push si push di call readline jmp _ihdlr_fin _ihdlr_3: cmp ah, 03h jne _ihdlr_4 push si push di push bx call load_file jmp _ihdlr_fin _ihdlr_4: cmp ah, 04h jne _ihdlr_5 call file_exists jmp _ihdlr_fin _ihdlr_5: _ihdlr_fin: iret prep_i13: xor dx, dx div word [fs:bpSectorsPerTrack] push dx xor dx, dx div word [fs:bpHeads] mov ch, al mov dh, dl mov dl, byte [fs:bpDriveNo] pop ax mov cl, al mov al, 1 mov ah, 2 ret fileoffset dw 0