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: