Now we are going to make our operating system do something when we type a command.
In demoos.asm take the following code:
mov ah, 009h ; Service string output mov dx, version ; dx is set to offset version int 021h
Move it down below jmp main then just before it add the following:
;------------------------------------------------------- ; Version Command ; Input: ; None ; Output: ; AX, DX are Destroyed ;------------------------------------------------------- ver:
Just after it add the following:
ret
Where you copied the code from add the following:
call ver
Now we need to be able to test if we typed a command. Add the following code
;------------------------------------------------------- ; Compare Command ; Input: ; DS:SI = Command String ; ES:DI = Buffer String ; Output: ; Carry set if not equal ; Carry clear if equal ;------------------------------------------------------- cmpcmd: push ax ; Save registers push si push di cmpcmdnext: mov al, [es:di] ; Load char from command line inc di ; Point to next character call toup ; Convert to uppercase mov ah, [ds:si] ; Load char to test against inc si ; Point to next character cmp ah, al ; Compare both characters jz cmpcmdnext ; If they are the same check next dec si ; Adjust to point to last char dec di cmp [ds:si], byte 0 ; Our test command end should be 0 jnz cmpcmdne ; If it isn't not our command cmp [es:di], byte ' ' ; Our input cmd might be space jz cmpcmde ; If it is this is our command cmp [es:di], byte 00Dh ; Our input cmd might be CR jz cmpcmde ; If it is this is our command jmp cmpcmdne ; Otherwise not our command cmpcmde: pop di ; Restore registers pop si pop ax clc ; Clear carry for match ret ; Return from subroutine cmpcmdne: pop di ; Restore registers pop si pop ax stc ; Set carry if not a match ret ; Return from subroutine
Now we need something to compare what we typed to. In the data area add:
verstr: db "VER", 0
Also while you are in the data area lets add a string for invalid commands.
invalid: db 00Dh, 00Ah, "Invalid Command" ; Message to be printed db 00Dh, 00Ah, '$'
Inside the main loop after we call the buffer lets do the check and call our new command.
mov di, buffer+2 ; Point to the string we typed mov si, verstr ; Point to command text call cmpcmd ; Compare jc cmdnver ; Carry set if not equal call ver ; Call function jmp main ; We're done checking cmdnver: mov ah, 009h ; Service Print String mov dx, invalid ; Invalid command int 021h ; Our Service call crlf ; New line
Then change:
version: db 00Dh, 00Ah, "DEMO OS V0.04" ; Message to be printed db 00Dh, 00Ah, '$'
to
version: db 00Dh, 00Ah, "DEMO OS V0.05" ; Message to be printed db 00Dh, 00Ah, '$'
;======================================================= ; Demo OS - demoos.asm ; ----------------------------------------------------- ; Written in NASM ; Written by Marcus Kelly ;======================================================= org 00000h ; Assemble code for this offset start: cli ; Turn off interrupts cld ; Make sure we are going forward mov ax, cs ; Set all segments to code segment mov ds, ax ; Make sure data segment is zero mov es, ax ; Make sure extra segment is zero mov ss, ax ; Make sure stack segment is zero mov sp, 07C00h ; Place stack ptr before boot sector sti ; Turn on interrupts call intinit ; Initialize interrupts call ver main: call crlf ; Print carriage return / line feed mov ah, 002h ; Service standard output mov dl, '>' ; Print '>' int 021h mov dl, ' ' ; Print Space int 021h mov ah, 00Ah ; Service string input mov dx, buffer ; Set dx to our buffer int 021h call crlf ; Print carriage return / line feed mov di, buffer+2 ; Point to the string we typed mov si, verstr ; Point to command text call cmpcmd ; Compare jc cmdnver ; Carry set if not equal call ver ; Call function jmp main ; We're done checking cmdnver: mov ah, 009h ; Service Print String mov dx, invalid ; Invalid command int 021h ; Our Service call crlf ; New line jmp main ; Repeat forever ;------------------------------------------------------- ; Compare Command ; Input: ; DS:SI = Command String ; ES:DI = Buffer String ; Output: ; Carry set if not equal ; Carry clear if equal ;------------------------------------------------------- cmpcmd: push ax ; Save registers push si push di cmpcmdnext: mov al, [es:di] ; Load char from command line inc di ; Point to next character call toup ; Convert to uppercase mov ah, [ds:si] ; Load char to test against inc si ; Point to next character cmp ah, al ; Compare both characters jz cmpcmdnext ; If they are the same check next dec si ; Adjust to point to last char dec di cmp [ds:si], byte 0 ; Our test command end should be 0 jnz cmpcmdne ; If it isn't not our command cmp [es:di], byte ' ' ; Our input cmd might be space jz cmpcmde ; If it is this is our command cmp [es:di], byte 00Dh ; Our input cmd might be CR jz cmpcmde ; If it is this is our command jmp cmpcmdne ; Otherwise not our command cmpcmde: pop di ; Restore registers pop si pop ax clc ; Clear carry for match ret ; Return from subroutine cmpcmdne: pop di ; Restore registers pop si pop ax stc ; Set carry if not a match ret ; Return from subroutine ;------------------------------------------------------- ; Version Command ; Input: ; None ; Output: ; AX, DX are Destroyed ;------------------------------------------------------- ver: mov ah, 009h ; Service string output mov dx, version ; dx is set to offset version int 021h ; Call the service call crlf ret %include "io.asm" %include "int.asm" ;------------------------------------------------------- ; Data Area ;------------------------------------------------------- verstr: db "VER", 0 version: db 00Dh, 00Ah, "DEMO OS V0.05" ; Message to be printed db 00Dh, 00Ah, '$' invalid: db 00Dh, 00Ah, "Invalid Command" ; Message to be printed db 00Dh, 00Ah, '$' buffer: db 64 ; Buffer for string input db 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0
Open io.asm and add the following:
;------------------------------------------------------- ; To Upper Case ; Input: ; al = Character ; Output: ; al = Character ;------------------------------------------------------- toup: cmp al, 'a' ; Compare to "a" jl toupdone ; If less than a don't change cmp al, 'z' ; Compare to "z" jg toupdone ; If greater than z don't change and al, 0DFh ; Remove uppercase bit toupdone: ret ; Return from subroutine
;======================================================= ; Input / Output - io.asm ; ----------------------------------------------------- ; Written in NASM ; Written by Marcus Kelly ;======================================================= ;------------------------------------------------------- ; Standard Output ; Input: ; DL = Character to print ; Output: ; AL = Input Character ;------------------------------------------------------- stdout: mov al, dl ; Place character in al push ax ; Save ax push bx ; Save bx mov ah, 00Eh ; BIOS Service Print Character mov bx, 00007h int 010h pop bx ; Restore bx pop ax ; Restore ax ret ; Return from subroutine ;------------------------------------------------------- ; String Output ; Input: ; DS:DX = String to print ; Output: ; AL = '$' ;------------------------------------------------------- strout: push dx ; Save dx push si ; Save si mov si, dx ; Move string pointer to si stroutnext: lodsb ; Get character from string cmp al, '$' ; Check end of string jz stroutdone ; if yes we are done mov dl, al ; Move char to dl for stdout call stdout ; Call stdout jmp stroutnext ; Next character stroutdone: pop si ; Restore si pop dx ; Restore di mov ah, 9 ; Place 9 back into ah ret ; Return from subroutine ;------------------------------------------------------- ; Standard Input ; Input: ; None ; Output: ; AL = Character ;------------------------------------------------------- stdin: xor ax, ax ; Wait for key BIOS Call int 016h mov ah, 8 ; Restore ah to 8 ret ; Return from subroutine ;------------------------------------------------------- ; String Input ; Input: ; DS:DX = Input Buffer Structure ; db Buffer Size ; dw 0 (This has a function we aren't using) ; db rep[Buffer Size] ; Output: ; DS:DX+3 = Input String ;------------------------------------------------------- strin: push ax ; Save registers push bx push cx push dx push di push es push ds ; Move ds to es pop es mov di, dx ; Move dx to di xor ch, ch mov cl, [es:di] ; cl = buffer size remaining or cl, cl ; if cl is zero we are done jz strindone add di, 2 ; Skip to start of buffer mov bx, di ; Save start of buffer strinnext: call stdin ; Wait for key press cmp al, 0x0d ; Check if enter was pressed jz strinenter ; if yes exit routine cmp al, 0x08 ; Check if backspace was pressed jz strinbs ; if yes goto backspace or cl, cl ; Check if buffer is full jz strinbf ; if yes goto buffer full mov dl, al ; Otherwise output character call stdout stosb ; Store character in the buffer dec cl ; Decriment buffer size remaining jmp strinnext ; Get next character strinbs: cmp di, bx ; Check if we are at buffer start jz strinnext ; if yes skip and get next key dec di ; Overwrite previous character mov al, 0 ; in memory stosb dec di ; Backup 1 space in memory mov dl, 8 ; Overwrite previous character call stdout ; on the screen mov dl, 0 call stdout mov dl, 8 ; Backup 1 space on screen call stdout inc cl ; Add 1 to buffer size remaining jmp strinnext ; Get next character strinbf: jmp strinnext ; Buffer full get next character strinenter: stosb ; Store 00Dh in the buffer dec cl ; Add it to the count mov ax, [es:bx-2] ; get buffer size sub ax, cx ; subtract remaining to get length dec ax ; 0D does not count in lenght mov [es:bx-1], al ; Store length in buffer strindone: pop es ; Restore registers pop di pop dx pop cx pop bx pop ax ret ; Return from subroutine ;------------------------------------------------------- ; Carrige Return / Line Feed ; Input: ; None ; Output: ; None ;------------------------------------------------------- crlf: push ax ; Save registers push dx mov dl, 00Dh ; Output carriage return call stdout mov dl, 00Ah ; Output line feed call stdout pop dx ; Restore registers pop ax ret ; Return from subroutine ;------------------------------------------------------- ; To Upper Case ; Input: ; al = Character ; Output: ; al = Character ;------------------------------------------------------- toup: cmp al, 'a' ; Compare to "a" jl toupdone ; If less than a don't change cmp al, 'z' ; Compare to "z" jg toupdone ; If greater than z don't change and al, 0DFh ; Remove uppercase bit toupdone: ret ; Return from subroutine
Now lets build our disk. If you are running the previous tutorial in VirtualBox Remember to remove the disk or close virtual box before assembling the disk image.
> nasm demoos.asm -o demoos.bin > nasm osdisk.asm -o osdisk.img
Your osdisk.img can now be loaded with VirtualBox. The result should be as follows:
DEMO OS V0.05 > ver DEMO OS V0.05 >Basics: Service | Index | Basics: CLS