/
shell.asm
168 lines (165 loc) · 3.1 KB
/
shell.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
bits 16
org 0x7c00
start:
; setup segments
mov bp, 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, bp
loop:
; execution falls through to here
; loop
mov si, prompt
call print
call read_line
mov si, line_buffer
call interpret
jmp loop
print:
; prints string in si
.print_repeat:
lodsb
cmp al, 0
je .print_end
mov ah, 0x0e
int 0x10
jmp .print_repeat
.print_end:
ret
print_newline:
mov ah, 0x0e
mov al, 0x0d ; carriage return
int 0x10
mov ah, 0x0e
mov al, 0x0a ; newline
int 0x10
ret
print_line:
call print
call print_newline
ret
read_line:
; reads one line into line_buffer
mov di, line_buffer
; clear string buffer
mov [di], byte 0
mov cx, 0 ; string length
.read_line_repeat:
; read char
mov ah, 0x00
int 0x16
; is it a backspace?
cmp al, 0x08
; jump to backspace handler
je .read_line_backspace
; echo char
mov ah, 0x0e
; char is already in al register
int 0x10
; is it a carriage return (enter)?
cmp al, 0x0d
; if so, break out of loop
je .read_line_end
; else, add to buffer
stosb
; increment string length
inc cx
jmp .read_line_repeat
.read_line_backspace:
; do nothing if string length is 0
cmp cx, 0
je .read_line_repeat
; decrement pointer and length
dec di
dec cx
; move cursor back
mov ah, 0x0e
mov al, 0x08
int 0x10
; output empty character
mov al, ' '
int 0x10
; and move the cursor back again with a backspace char
mov al, 0x08
int 0x10
jmp .read_line_repeat
.read_line_end:
; add null terminator
mov al, 0
stosb
; print newline char
mov ah, 0x0e
mov al, 0x0a
int 0x10
ret
compare_strings:
; compares strings in the registers si and di, returns 0 in ax if false and 1 in ax otherwise
push si
push di
.compare_strings_loop:
mov al, byte [si]
cmp byte [di], al
jne .compare_strings_not_equals
cmp byte [si], byte 0
je .compare_strings_equals
inc si
inc di
jmp .compare_strings_loop
.compare_strings_not_equals:
mov ax, 0
pop di
pop si
ret
.compare_strings_equals:
mov ax, 1
pop di
pop si
ret
; interpreter
interpret:
; command string is in si register
mov bx, 0
.interpret_loop:
cmp [commands + bx], byte 0
je .interpret_error
mov di, [commands + bx]
; compare strings
call compare_strings
cmp ax, 1
je .interpret_end
add bx, 4
jmp .interpret_loop
.interpret_end:
add bx, 2
call [commands + bx]
ret
.interpret_error:
mov di, si ; relocation
mov si, interpret_error_msg
call print
mov si, di ; put back into si
call print
mov ah, 0x0e
mov al, "'"
int 0x10
call print_newline
ret
; commands
echo_command:
call read_line
mov si, line_buffer
call print_line
ret
prompt: db "$ ", 0
interpret_error_msg: db "Unknown command '", 0
line_buffer: equ 0x7e00 ; line buffer
echo_str: db "echo", 0
commands: ; list of commands
dw echo_str,
dw echo_command,
dw 0,
dw 0 ; terminator
times 510-($-$$) db 0
dw 0xaa55