This repository has been archived by the owner on Dec 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootloader.asm
317 lines (242 loc) · 6.9 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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
org 7C00h ;start at
bits 16 ;16bit real mode
%define endl 0Dh, 0Ah
jmp setup ;go back to your place bitch
; FAT12 HEADER
bdb_oem: db 'MSWIN4.1' ; 8 bytes
bdb_bytes_per_sector: dw 512
bdb_sectors_per_cluster: db 1
bdb_reserved_sectors: dw 1
bdb_fat_count: db 2
bdb_dir_entries_count: dw 0E0h
bdb_total_sectors: dw 2880 ; 2880 * 512 = 1.44MB
bdb_media_descriptor_type: db 0F0h ; F0 = 3.5" floppy disk
bdb_sectors_per_fat: dw 9 ; 9 sectors/fat
bdb_sectors_per_track: dw 18
bdb_heads: dw 2
bdb_hidden_sectors: dd 0
bdb_large_sector_count: dd 0
; EBR SECTION
ebr_drive_number: db 0 ; 0x00 floppy, 0x80 hdd, useless
ebr_useless: db 0 ; reserved, windows stuff, i guess
ebr_signature: db 29h
ebr_volume_id: db 12h, 34h, 56h, 78h ; serial number, value doesn't matter
ebr_volume_label: db 'GOLD OS ' ; 11 bytes, padded with spaces
ebr_system_id: db 'FAT12 ' ; 8 bytes db 'FAT12 ' ; 8 bytes
; END OF HEADER
;MAIN AREA
;setup registers and stack
setup:
;setup registers
mov ax, 0 ;clear ax
mov ds, ax ;clear ds by copying ax
mov es,ax ;clear es by copying ax
;setup stack
mov ss, ax ;clear ss by copying ax
mov sp, 0x7c00 ;set stack to work without overwriting our stuff
;set disk number
mov [ebr_drive_number], dl
jmp kernel_find
;says shit
;PARAMS: si - String to print.
;RETURNS: nothing
talk:
;save registers to stack
push si
push ax
.loop:
lodsb ;load next character in al
or al, al ;verify if next character is null
jz .done ;if null then complete
;BIOS INTERRUPT, SEE RESOURCES.md
mov ah, 0eh ;print character
mov bh, 0 ;page 0
int 10h ;INTERRUPT VIDEO SERVICE
jmp .loop ;restart
.done:
pop ax
pop si
ret
;reboot function
reboot:
jmp 0FFFFh:0 ;jump to beginning of bios
;DISK AREA
;converts LBA(logical block addressing) address to CHS(cylinder, head, sector) address
;PARAMS: ax - LBA Address.
;RETURNS: cx[0-5] - Sector number.
; : cx[6-15] - Cylinder.
; : dh - Head.
disk_lba_chs_conversion:
;save registers that are used, but are not part of param or input
push ax
push dx
xor dx, dx ;clear dx register
div word [bdb_sectors_per_track] ;ax = LBA Address / Sectors per Track
;dx = LBA Address % Sectors per Track
inc dx ;dx = the previous operation + 1 = sector
mov cx, dx ;send to the correct output register
xor dx, dx ;clear dx
div word [bdb_heads] ;ax = (address / sectors per track) / Heads = cylinder
;dx = (address / sectors per track) % Heads = head
mov dh, dl ;send value to output location
;dl = lower 8 bits of dx
mov ch, al ;ye same shit
shl ah, 6 ;shift 6 bits to left
or cl, ah ;move the data, don't replace everything
; restore registers
pop ax
mov dl, al
pop ax
ret
floppy_error:
mov si, ferror_read_failed
call talk
call fatal_reboot
;reads the disk
;PARAMS: ax - LBA Address.
; : cl - nuber of sectors to read.
; : dl - drive number.
; : es:bx - memory address to store the data.
;RETURNS: (relative) - data read.
disk_read:
pusha ; save registers we will modify
push cx ; temporarily save CL (number of sectors to read)
call disk_lba_chs_conversion ; compute CHS
pop ax ; AL = number of sectors to read
mov ah, 02h
mov di, 3 ; retry count
.retry:
pusha ; save all registers, we don't know what bios modifies
stc ; set carry flag, some BIOS'es don't set it
int 13h ; carry flag cleared = success
jnc .done ; jump if carry not set
; read failed
popa
call disk_reset
dec di
test di, di
jnz .retry
.fail:
; all attempts are exhausted
jmp floppy_error
.done:
popa ; restore registers
ret
disk_reset:
pusha
mov ah, 0
stc
int 13h
jc floppy_error
popa
ret
;KERNEL LOAD AREA
KERNEL_LOAD_SEGMENT equ 0x2000
KERNEL_LOAD_OFFSET equ 0
kernel_cluster: dw 0
;just gets the size of the root directory
kernel_find:
;get root directory address
mov ax, [bdb_sectors_per_fat]
mov bl, [bdb_fat_count]
xor bh, bh
mul bx
add ax, [bdb_reserved_sectors]
push ax
;get size of root directory
mov ax, [bdb_sectors_per_fat]
shl ax, 5
xor dx, dx
div word [bdb_bytes_per_sector]
test dx, dx
jz .rdsdone
inc ax
.rdsdone:
;read root diretory
mov cl, al
pop ax
mov dl, [ebr_drive_number]
mov bx, buffer
call disk_read
;find the kernel
xor bx, bx
mov di, buffer
.kernelsearch:
mov si, file_kernel
mov cx, 11
push di
repe cmpsb
pop di
je .kernelfound
add di, 32
inc bx
cmp bx, [bdb_dir_entries_count]
jl .kernelsearch
mov si, ferror_no_kernel
call talk
call fatal_reboot
.kernelfound:
mov ax, [di + 26]
mov [kernel_cluster], ax
;get stuff from disk
mov ax, [bdb_reserved_sectors]
mov bx, buffer
mov cl, [bdb_sectors_per_fat]
mov dl, [ebr_drive_number]
call disk_read
mov bx, KERNEL_LOAD_SEGMENT
mov es, bx
mov bx, KERNEL_LOAD_OFFSET
.kernelload:
mov ax, [kernel_cluster]
;awfull shit, only safe in floppy disk
add ax, 31
mov cl, 1
mov dl, [ebr_drive_number]
call disk_read
add bx, [bdb_bytes_per_sector] ;awfull shit, will overflow if kernel above 64kb, will overwrite if it happens
mov ax, [kernel_cluster]
mov cx, 3
mul cx
mov cx, 2
div cx
mov si, buffer
add si, ax
mov ax, [ds:si]
or dx, dx
jz .even
.odd:
shr ax, 4
jmp .continue
.even:
and ax, 0x0FFF
.continue: ;didn't have a better name
cmp ax, 0x0FF8
jae .finishreading
mov [kernel_cluster], ax
jmp .kernelload
.finishreading: ;time to go to bed, hehe
mov dl, [ebr_drive_number]
mov ax, KERNEL_LOAD_SEGMENT
jmp KERNEL_LOAD_SEGMENT:KERNEL_LOAD_OFFSET ;goodbye
mov si, ferror_kernel_jump_failed
call talk
call fatal_reboot
ret
;STRING AREA
file_kernel: db "KERNEL BIN"
ferror_no_kernel: db "FATAL ERROR: Kernel Not Found", endl, 0
ferror_read_failed: db "FATAL ERROR: Disk read operation Failed", endl, 0 ;message for when it can't read the disk.
ferror_kernel_jump_failed: db "FATAL ERROR: Jump to Kernel Failed"
; MISC AREA
;reboots in case of fatal error
fatal_reboot:
;BIOS INTERRUPT, SEE RESOURCES.md
mov ah, 0 ;wait for keypress
int 16h ;INTERRUPT KEYBOARD SERVICE
jmp reboot
ret
buffer: ;label to unused bootloader space, protected from stack, sure, it can overwrite the signature, but at that time it's already useless
times 510-($-$$) db 0 ;nullify the rest of the 512 bytes we can use
dw 0AA55h ;bootloader signature, DO NOT TOUCH, DON'T EVEN THINK ABOUT IT.
;everything beyond this point will not be protected and can be overwritten by the stack, write at your own risk.