-
Notifications
You must be signed in to change notification settings - Fork 1
/
bootloader.asm
239 lines (184 loc) · 4.39 KB
/
bootloader.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
org 0x7c00
jmp 0:start
ASCII_BACKSPACE equ 0x08
ASCII_RETURN equ 0x0d
ASCII_NEWLINE equ 0x0a
ASCII_NULL equ 0x00
ASCII_SPACE equ 0x20
INT_VECTOR_VIDEO equ 0x10
INT_VECTOR_DRIVE equ 0x13
INT_VECTOR_MISC equ 0x15
INT_VECTOR_KEYBOARD equ 0x16
VIDEO_PRINT equ 0x0e
MISC_WAIT equ 0x86
DRIVE_READ_SECTOR equ 0x02
DRIVE_WRITE_SECTOR equ 0x03
MIN_USERNAME_LENGTH equ 3
MAX_USERNAME_LENGTH equ 12
; CONST STRINGS
INPUT_MESSAGE: db 'Enter your name', ASCII_RETURN, ASCII_NEWLINE, ASCII_NULL
WELCOME_MESSAGE: db 'Hello '
NAME: db ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL
ENDL: db ASCII_RETURN, ASCII_NEWLINE, ASCII_NULL
DRIVE: dw 0x00
; Sets bx to NAME[%1] pointer
%macro get_name_index 1
mov bx, NAME
add bx, %1
%endmacro
; Wrapper for print_char function
%macro print_char_macro 1
mov al, %1
call print_char
%endmacro
; Wrapper for print function
%macro print_macro 1
mov ax, %1
call print
%endmacro
; Call wait sectors BIOS interrupt
%macro wait 0
mov ah, MISC_WAIT
int INT_VECTOR_MISC
%endmacro
; Prepares registers for drive sector read (write)
; @param 1 source (destination) for read (write)
%macro prepare_drive 1
; Source (Destination) sector = %1
mov cl, %1
; Track = 0
xor ch, ch
; Head = 0
xor dh, dh
; Sectors Count = 1
mov al, 0x01
; Set drive
mov dl, [DRIVE]
%endmacro
; Call write sectors BIOS interrupt
%macro write_sectors 0
mov ah, DRIVE_WRITE_SECTOR
int INT_VECTOR_DRIVE
%endmacro
; Call read sectors BIOS interrupt
%macro read_sectors 0
mov ah, DRIVE_READ_SECTOR
int INT_VECTOR_DRIVE
%endmacro
; Prints character
; @param `al` character to print
print_char:
mov ah, VIDEO_PRINT
int INT_VECTOR_VIDEO
ret
; Reads character
; @returns `al` character
read_char:
xor ah, ah
int INT_VECTOR_KEYBOARD
ret
; Prints null terminated string
; @param `ax` pointer to first letter
print:
mov bx, ax
print_loop:
mov al, [bx]
; Finish if it's a null character
test al, al
jz print_end
; Otherwise print it
call print_char
; Continue with the next character
inc bx
jmp print_loop
print_end:
ret
start:
init_registers:
; Save drive number for future operations
mov [DRIVE], dl
; Set all registers to 0
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
; Initialize stack
init_stack:
mov sp, 0x8000
; Print "Enter your name\r\n" message
input:
mov ax, INPUT_MESSAGE
call print
; Read characters
read_username:
xor cx, cx
read_username_loop:
call read_char
cmp al, ASCII_RETURN
je read_username_return
cmp al, ASCII_BACKSPACE
je read_username_backspace
cmp cx, MAX_USERNAME_LENGTH
jge read_username_loop
read_username_char:
call print_char
; Set NAME[index] to character in al
get_name_index cx
mov [bx], al
; Increase length and continue
inc cx
jmp read_username_loop
read_username_backspace:
; If the name is empty continue the loop
test cx, cx
jz read_username_loop
; Remove previous character from screen
call print_char
print_char_macro ASCII_SPACE
print_char_macro ASCII_BACKSPACE
; Set NAME[index] to null character
get_name_index cx
mov byte [bx], ASCII_NULL
; Decrease length
dec cx
jmp read_username_loop
read_username_return:
; If the name is long enough go to end
cmp cx, MIN_USERNAME_LENGTH
jge read_username_end
; Else
jmp read_username_loop
read_username_end:
; Print endl
print_macro ENDL
; Print welcome message and name as WELCOME_MESSAGE is not null
; terminated and NAME is in memory right after WELCOME_MESSAGE
print_macro WELCOME_MESSAGE
; Print endl
print_macro ENDL
save_username:
prepare_drive 0x03
; Set source address to NAME
mov bx, NAME
write_sectors
wait_2s:
; 0x8480 + 0xffff * 0x1e = 0x1e8480
mov dx, 0x8480
mov cx, 0x1e
wait
load_copy_instructions:
prepare_drive 0x02
mov bx, 0x7e00
read_sectors
jmp 0x7e00
; Fill the rest with zeros and add 0xaa55 sequence
times (510 - $ + $$) db 0
dw 0xaa55
; Second drive secotor (won't be overriden by drive load)
copy_minix_bootloader:
prepare_drive 0x04
; Set destination to standard bootloader place
mov bx, 0x7c00
read_sectors
jmp 0x7c00
times (1024 - $ + $$) db 0