EttinOS/src/SYSTEM.ASM

294 lines
4.6 KiB
NASM

CPU 8086
ORG 0x500
jmp start
;Interrupt handler
;Return to the shell
int0x20:
jmp shell
;Input and output
int0x21:
cmp ah, 0x0
je printstr
cmp ah, 0x1
je readstr
cmp ah, 0x2
je println
cmp ah, 0x3
je readln
iret
;Disk operations
int0x22:
cmp ah, 0x0
je loadf
;To do: savef
iret
;System calls
%include "PRINTSTR.INC"
%include "READSTR.INC"
%include "PRINTLN.INC"
%include "READLN.INC"
%include "LOADF.INC"
start:
;Set up the interrupt vectors
;Interrupt 0x20 offset
mov ax, int0x20
mov [0x80], ax
;Interrupt 0x21 offset
mov ax, int0x21
mov [0x84], ax
;Interrupt 0x22 offset
mov ax, int0x22
mov [0x88], ax
;Segments
mov ax, 0x0
mov [0x82], ax
mov [0x86], ax
mov [0x8a], ax
;Store the boot drive number and set the drive letter
mov [drive], dl
call setdriveletter
;Print a welcome message
mov si, welcomemsg
mov ah, 0x2
int 0x21
shell:
;Re-set the stack
cli
mov sp, 0x0
sti
;Prompt for and read a command
;Print the drive letter
mov si, driveletter
mov ah, 0x0
int 0x21
;Print a prompt
mov si, prompt
mov ah, 0x0
int 0x21
;Read
mov di, input
mov al, 0x4c
mov ah, 0x3
int 0x21
;Check for non-program stuff
;Check for an empty command
cmp byte [input], 0x0
jz shell
;Check for a drive change command
mov si, input + 0x1
mov di, driveletter + 0x1
call cmpstr
jnc changedrive
;Extract the program name
;Set SI at input and DI at program
mov si, input
mov di, program
;Ignore leading spaces
call ignoreleading
;Initialise program with spaces
mov cx, 0xc
mov al, 0x20
rep stosb
sub di, 0xc
;Initialise the length counter
mov bl, 0x8
extractprog:
;Load a character
lodsb
;Check for the string end
cmp al, 0x0
je addext
;Check for a space
cmp al, 0x20
je addext
;Check for the length limit
cmp bl, 0x0
je cmderror
;Store the character
stosb
;Decrease the counter
dec bl
jmp extractprog
;Add extension to the name
addext:
push si
mov si, extension
mov cx, 0x5
rep movsb
;Load and execute the program
;Load
mov bx, 0x2000
;mov si, input
mov si, program
mov ah, 0x0
int 0x22
;Check for errors
cmp al, 0x1
je cmderror
;Pass the command tail to the program
pop si
call ignoreleading
;Execute
jmp 0x2000
;Print a command error message and return to the shell
cmderror:
mov si, cmderrormsg
mov ah, 0x2
int 0x21
jmp shell
;Change the drive
changedrive:
;Check which drive to change to
cmp byte [input], "a"
je .a
cmp byte [input], "A"
je .a
cmp byte [input], "b"
je .b
cmp byte [input], "B"
je .b
cmp byte [input], "c"
je .c
cmp byte [input], "C"
je .c
cmp byte [input], "d"
je .d
cmp byte [input], "D"
je .d
;Print a drive error message and return to the shell
mov si, driverrormsg
mov ah, 0x2
int 0x21
jmp shell
;Change
.a:
mov dl, 0x0
mov byte [drive], dl
call setdriveletter
jmp shell
.b:
mov dl, 0x1
mov byte [drive], dl
call setdriveletter
jmp shell
.c:
mov dl, 0x2
mov byte [drive], dl
call setdriveletter
jmp shell
.d:
mov dl, 0x3
mov byte [drive], dl
call setdriveletter
jmp shell
;Data
welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0
drive db 0x0
driveletter db "?:", 0x0
prompt db "> ", 0x0
input times 0x4c db 0x0
program times 0xd db 0x0
extension db ".BIN", 0x0
cmderrormsg db "Unknown command", 0x0
driverrormsg db "Unknown drive", 0x0
crlf db 0xd, 0xa, 0x0
;Set the drive letter
setdriveletter:
;Check the drive number
cmp dl, 0x0
je .a
cmp dl, 0x1
je .b
cmp dl, 0x2
je .c
cmp dl, 0x3
je .d
ret
;Set
.a:
mov byte [driveletter], "A"
ret
.b:
mov byte [driveletter], "B"
ret
.c:
mov byte [driveletter], "C"
ret
.d:
mov byte [driveletter], "D"
ret
;Compare two strings ending in a null at SI and DI and clear the carry flag if they are equal and set it if not
cmpstr:
;Store the initial registers in the stack
push ax
push bx
;Compare the strings
.loop:
;Load the current characters
mov al, [si]
mov bl, [di]
;Compare the characters
cmp al, bl
;Check for difference
jne .neq
;Check for the string end
cmp al, 0x0
je .eq
;Repeat for the next characters
inc si
inc di
jmp .loop
;Clear the carry flag
.eq:
clc
jmp .done
;Set the carry flag
.neq:
stc
.done:
;Load the initial registers from the stack
pop bx
pop ax
ret
;Ignore leading spaces in the command and its tail
ignoreleading:
lodsb
cmp al, 0x20
je ignoreleading
dec si
ret
;Print a CRLF
printcrlf:
;Store the initial registers in the stack
push si
;Print the CRLF
mov si, crlf
mov ah, 0x0
int 0x21
;Load the initial registers from the stack
pop si
ret
;File system buffer
buffer: