274 lines
4.1 KiB
NASM
274 lines
4.1 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 an empty command
|
||
cmp byte [input], 0x0
|
||
jz shell
|
||
|
||
;Check for a drive change command
|
||
;Set SI at input
|
||
mov si, input
|
||
;Ignore leading spaces
|
||
call ignoreleading
|
||
;Check
|
||
inc si
|
||
cmp byte [si], ":"
|
||
jne exec
|
||
inc si
|
||
cmp byte [si], 0x0
|
||
je changedrive
|
||
cmp byte [si], 0x20
|
||
je changedrive
|
||
|
||
;Execute a program
|
||
exec:
|
||
|
||
;Extract the filename
|
||
;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
|
||
;Load
|
||
mov bx, 0x2000
|
||
mov si, program
|
||
mov ah, 0x0
|
||
int 0x22
|
||
;Check for errors
|
||
cmp al, 0x1
|
||
je cmderror
|
||
;Pass the drive and command tail to the program
|
||
mov dl, byte [drive]
|
||
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:
|
||
sub si, 0x2
|
||
;Check which drive to change to
|
||
cmp byte [si], "a"
|
||
je cha
|
||
cmp byte [si], "A"
|
||
je cha
|
||
cmp byte [si], "b"
|
||
je chb
|
||
cmp byte [si], "B"
|
||
je chb
|
||
cmp byte [si], "c"
|
||
je chc
|
||
cmp byte [si], "C"
|
||
je chc
|
||
cmp byte [si], "d"
|
||
je chd
|
||
cmp byte [si], "D"
|
||
je chd
|
||
;Print a drive error message and return to the shell
|
||
mov si, driverrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
jmp shell
|
||
;Change
|
||
cha:
|
||
mov dl, 0x0
|
||
mov byte [drive], dl
|
||
call setdriveletter
|
||
jmp shell
|
||
chb:
|
||
mov dl, 0x1
|
||
mov byte [drive], dl
|
||
call setdriveletter
|
||
jmp shell
|
||
chc:
|
||
mov dl, 0x2
|
||
mov byte [drive], dl
|
||
call setdriveletter
|
||
jmp shell
|
||
chd:
|
||
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
|
||
|
||
;Set the drive letter
|
||
setdriveletter:
|
||
;Check the drive number
|
||
cmp dl, 0x0
|
||
je .seta
|
||
cmp dl, 0x1
|
||
je .setb
|
||
cmp dl, 0x2
|
||
je .setc
|
||
cmp dl, 0x3
|
||
je .setd
|
||
ret
|
||
;Set
|
||
.seta:
|
||
mov byte [driveletter], "A"
|
||
ret
|
||
.setb:
|
||
mov byte [driveletter], "B"
|
||
ret
|
||
.setc:
|
||
mov byte [driveletter], "C"
|
||
ret
|
||
.setd:
|
||
mov byte [driveletter], "D"
|
||
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
|
||
;Data
|
||
.crlf db 0xd, 0xa, 0x0
|
||
|
||
;File system buffer
|
||
buffer:
|
||
|