diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2018-06-19 00:54:43 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2018-06-19 00:54:43 -0400 |
commit | 47e691cb0b7a49a797c622b6c79162428358fbe1 (patch) | |
tree | 11cbfcd397d92567953507a0f8482d269bd299d6 | |
parent | 16ce91dac78f9a522d6b5a5f4b0f651e25635a4f (diff) | |
download | minos-47e691cb0b7a49a797c622b6c79162428358fbe1.tar.gz |
Implement builtin terminal commands
* Reboot
* Exit
* Echo
-rw-r--r-- | builtin_echo.asm | 20 | ||||
-rw-r--r-- | builtin_exit.asm | 17 | ||||
-rw-r--r-- | builtin_reboot.asm | 29 | ||||
-rw-r--r-- | builtins.asm | 19 | ||||
-rw-r--r-- | terminal.asm | 152 |
5 files changed, 214 insertions, 23 deletions
diff --git a/builtin_echo.asm b/builtin_echo.asm new file mode 100644 index 0000000..1b4af89 --- /dev/null +++ b/builtin_echo.asm @@ -0,0 +1,20 @@ +%ifndef _BUILTIN_ECHO_ASM +%define _BUILTIN_ECHO_ASM + +builtin_echo: + push bp + mov bp, sp + + mov bx, word [bp + 4] + add bx, 2 + push word [bx] + push .msg_fmt + call printf + add sp, 2 * 2 + + mov sp, bp + pop bp + ret + .msg_fmt db '%s\n', 0 + +%endif diff --git a/builtin_exit.asm b/builtin_exit.asm new file mode 100644 index 0000000..74594e1 --- /dev/null +++ b/builtin_exit.asm @@ -0,0 +1,17 @@ +%ifndef _BUILTIN_EXIT_ASM +%define _BUILTIN_EXIT_ASM + +builtin_exit: + push bp + mov bp, sp + + push .msg_fmt + call printf + add sp, 2 * 1 + + add sp, 2 ; cleanup previous call address + + jmp terminal + .msg_fmt db 'exiting...\n', 0 + +%endif diff --git a/builtin_reboot.asm b/builtin_reboot.asm new file mode 100644 index 0000000..54d6f8a --- /dev/null +++ b/builtin_reboot.asm @@ -0,0 +1,29 @@ +%ifndef _BUILTIN_REBOOT_ASM +%define _BUILTIN_REBOOT_ASM + +builtin_reboot: + mov bx, 3 ; number of seconds + .countdown: + push bx + push .msg_reboot_count + call printf + add sp, 2 * 2 + + mov ah, 86h + mov cx, 0fh + mov dx, 4240h + int 15h + + dec bx + jne .countdown + + push .msg_reboot + call printf + add sp, 2 * 1 + + jmp 0FFFFh:0000h ; issue reboot + .msg_reboot_count db 'rebooting in %d seconds...\r', 0 + .msg_reboot db '\nreboot...\n', 0 + ; no return, and the stack is irrelevant here + +%endif diff --git a/builtins.asm b/builtins.asm new file mode 100644 index 0000000..268e4b2 --- /dev/null +++ b/builtins.asm @@ -0,0 +1,19 @@ +%ifndef _BUILTINS_ASM +%define _BUILTINS_ASM + +%include "builtin_reboot.asm" +%include "builtin_exit.asm" +%include "builtin_echo.asm" + +t_builtins_fn: + dw builtin_echo + dw builtin_exit + dw builtin_reboot + dw 0 + +t_builtins_str: + .echo: db 'echo', 0 + .exit: db 'exit', 0 + .reboot: db 'reboot', 0 + dw 0 +%endif diff --git a/terminal.asm b/terminal.asm index 376595a..718a304 100644 --- a/terminal.asm +++ b/terminal.asm @@ -1,16 +1,18 @@ %ifndef _TERMINAL_ASM %define _TERMINAL_ASM +%include "builtins.asm" + T_BUFSZ equ 255 ; maximum length of terminal input buffer + terminal: push bp mov bp, sp - push ds - push es mov ax, ds mov es, ax + sub sp, 2 ; variable for buffer start address sub sp, T_BUFSZ ; reserve space for tokens cld @@ -18,9 +20,9 @@ terminal: .clear_buffer: xor ax, ax mov cx, T_BUFSZ / 2 - lea di, [bp - T_BUFSZ] - mov dx, di - repne stosb ; zero out token storage + lea di, [bp - T_BUFSZ] ; load buffer start address + mov [bp - 2], di ; store start address for later + repne stosb ; zero out token storage xor ax, ax mov cx, T_BUFSZ / 2 ; counter is length of buffer @@ -45,6 +47,7 @@ terminal: cmp al, ASCII_CR ; return pressed? jne .update_buffer mov al, ASCII_LF ; convert CR to LF + mov byte [di], 0 .update_buffer: cmp al, ASCII_LF @@ -62,29 +65,20 @@ terminal: .flush_buffer: cmp [di-1], byte 0 ; stosb above increments di. ; (di - 1) is the previous input - je .do_prompt ; if no input (null), start over + je .clear_buffer ; if no input (null), start over mov al, ASCII_LF call putc ; print carriage return push ' ' - push dx - push t_buffer - call strtok + push word [bp - 2] ; token array address + push t_buffer ; address of terminal input buffer + call strtok ; tokenize add sp, 2 * 3 - push ax - call printh - add sp, 2 - - ; ---- TEMPORARY --- - ; a command parser will be here eventually - ; TODO: write string tokenizer - ;push t_buffer ; push buffer string address - ;push t_buffer_fmt ; push buffer format string address - ;call printf ; write input to console - ;add sp, 2 * 2 ; clean up stack - ; --- END TEMPORARY --- + push ax ; push token array + call terminal_check_input ; parse terminal input + add sp, 2 * 1 jmp .clear_buffer ; zero out buffer / start over @@ -95,13 +89,125 @@ terminal: jmp .do_prompt ; start over add sp, 2 - pop es - pop ds mov sp, bp pop bp ret +terminal_check_input: + %define .input_len [bp - 2] + %define .scan_count [bp - 4] + %define .compare_count [bp - 6] + %define .input_baseaddr [bp - 8] + %define .builtins_count [bp - 10] + + push bp + mov bp, sp + sub sp, 2 * 5 + + pusha + + mov bx, word [bp + 4] ; arg1 - Token array + mov .input_baseaddr, bx ; store base address of tokenized string + + mov cx, 0 ; Initialize scan counter + mov .scan_count, cx ; store initial counter value + + mov di, t_builtins_str ; Load destination index with a + ; list of builtin command + mov si, .input_baseaddr ; Load source index with the address + mov si, [si] ; Load the string at token address + + push si + call strlen + pop si + mov .input_len, ax ; identifiers (strings) + + mov cx, 0 + mov si, t_builtins_fn + .count_builtins: + cmp word [si], 0 + je .count_builtins_done + add si, 2 + inc cx + jmp .count_builtins + + .count_builtins_done: + mov word .builtins_count, cx + + .scan_builtins: + mov cx, .scan_count + cmp cx, .builtins_count + jge .scan_no_match + + + mov si, .input_baseaddr ; Load source index with the address + mov si, [si] ; Load the string at token address + + push di ; get the length of builtin string... + call strlen ; strtok returns pointers to the + pop di + ; beginning of a substring, so in order + ; to scan for matches, we need to know + ; how many bytes to compare ahead + ; of time. + + mov cx, .input_len + cmp ax, cx + jne .compare_prefail + + ;sub ax, 1 ; Modify strlen return value (+1 null terminator) + mov .compare_count, ax ; Store return value of strlen in counter + xor ax, ax + xor dx, dx + xor cx, cx + + .compare: + mov al, byte [si] ; Load byte from input string + mov dl, byte [di] ; Load byte from builtin identifier string + + cmp al, dl ; Compare bytes + jne .compare_fail ; bytes did not match, so try the next string + + dec word .compare_count ; decrement counter + je .return ; if counter == 0; return + + inc si ; Increment input string offset + inc di ; Increment builtin identifier string offset + jmp .compare ; ... continue + + .compare_fail: + inc word .scan_count ; Increment builtin identifier string attempt count + inc di + add di, word .compare_count ; Load the offset of the next builtin identifier + jmp .scan_builtins ; Continue scanning + + .compare_prefail: + inc word .scan_count + inc ax ; adjust for null terminator + add di, ax ; Load the offset of the next builtin identifier + jmp .scan_builtins + + + .return: + mov bx, t_builtins_fn ; Load address of function pointer array + mov cx, word .scan_count ; Load offset count + shl cx, 1 ; Multiply offset count by 2 (next WORD) + add bx, cx ; Add offset to address of function pointer array + + mov si, .input_baseaddr + push si ; address of next token + call word [bx] ; Execute builtin command + add sp, 2 * 1 + + .scan_no_match: + popa + add sp, 2 * 5 + mov sp, bp + pop bp + ret + + ; data t_msg_prompt_fmt: db '%s', 0 t_msg_prompt: db '$ ', 0 |