-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel.asm
More file actions
465 lines (415 loc) · 14.8 KB
/
kernel.asm
File metadata and controls
465 lines (415 loc) · 14.8 KB
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
; ==================================================================
; LuckyOS -- An Operating System kernel written in Assembly
; by Sachin. This OS is inspired by MikeOS. Great thanks
; to MikeOS for the MikeOS Developers.
; ==================================================================
BITS 16 ; We tell the assembler that this is a 16-bit program
ORG 0x1000 ; The bootloader loads us at this specific address (0x1000)
start:
; --- Initialize segment registers ---
; The bootloader jumps to 0x0000:0x1000. It's good practice for the kernel
; to set up its own segments, especially for consistency.
; Here we set DS, ES, SS to 0, matching the common practice of using
; the first 64KB for initial kernel operations in real mode.
xor ax, ax
mov ds, ax ; Set the Data Segment (DS) to 0
mov es, ax ; Also set ES for other operations
mov ss, ax ; Set SS (Stack Segment) to 0
mov sp, 0x7E00 ; Set SP to a location above 0x7C00 (bootloader)
; This creates a stack that grows downwards from 0x7E00
; (e.g., towards 0x7DFF, 0x7DFE, etc.).
call clear_screen ; Clear the screen at the start
mov si, welcome_string
call print_string
call print_newline
main_loop:
call print_newline
mov si, prompt_string
call print_string
mov di, command_buffer
call read_string
; --- COMMAND DISPATCHER ---
mov si, command_buffer
mov di, info_cmd
call string_compare
je handle_info_cmd
mov si, command_buffer
mov di, help_cmd ; Check for "help" command
call string_compare
je handle_help_cmd
mov si, command_buffer ; Check for "clear" command
mov di, clear_cmd
call string_compare
je handle_clear_cmd ; Jump to new handler for clear
mov si, unknown_cmd_string
call print_newline
call print_string
jmp main_loop
handle_info_cmd:
call show_hardware_info
jmp main_loop
handle_help_cmd:
call print_newline ; Add a newline before the help text
mov si, help_menu_string ; Print the help menu
call print_string
call print_newline ; Add a newline after the help text
jmp main_loop
handle_clear_cmd: ; New handler for the "clear" command
call clear_screen ; Call the clear screen routine
jmp main_loop ; Go back to the main loop
; ==================================================================
; MAIN HARDWARE INFO ROUTINE
; ==================================================================
show_hardware_info:
pusha
call print_newline
call detect_memory
call detect_cpu
call detect_drives
call detect_mouse
call detect_serial_ports
call detect_cpu_features
popa
ret
; --- Specialized Detection Subroutines ---
detect_memory:
; --- Base Memory ---
mov si, mem_base_label
call print_string
int 12h ; Returns base memory size in KB in AX
mov [base_mem_kb], ax
call print_decimal
call print_k_suffix
; --- Extended Memory (1M - 16M) ---
mov si, mem_ext_label
call print_string
mov ah, 0x88
int 0x15 ; Returns extended memory in KB in AX
mov [ext_mem_kb], ax
call print_decimal
call print_k_suffix
; --- Extended Memory (Above 16M) ---
mov si, mem_ext2_label
call print_string
mov ax, 0xE801
int 0x15
jc .no_e801 ; Jump if this function is not supported
mov [ext2_mem_16k_blocks], cx ; CX/DX has mem > 16M in 16KB blocks
mov [ext2_mem_64k_blocks], dx
; For simplicity, we'll use the 64KB block value. Convert to MB (DX / 16)
mov dx, 0 ; Clear DX for 32-bit division
mov ax, [ext2_mem_64k_blocks] ; AX will hold the low 16 bits of the 64k_blocks
movzx eax, ax ; Load AX into EAX (zero-extended)
mov ebx, 16 ; Divisor for 64KB blocks (64/16 = 4 bytes per block)
xor edx, edx ; Clear EDX for division
div ebx ; EAX = EAX / EBX (gives MB)
mov [ext2_mem_mb], ax ; Store the lower 16 bits (MB)
call print_decimal
call print_M_suffix
jmp .sum_total
.no_e801:
mov si, not_supported_str
call print_string
mov word [ext2_mem_mb], 0
; --- Total Memory ---
.sum_total:
mov si, mem_total_label
call print_string
; Calculate total KB first using EAX for 32-bit arithmetic
mov eax, 0 ; Clear EAX for total KB
movzx ebx, word [base_mem_kb] ; Load base_mem_kb into EBX (zero-extended)
add eax, ebx ; Add to EAX
movzx ebx, word [ext_mem_kb] ; Load ext_mem_kb into EBX (zero-extended)
add eax, ebx ; Add to EAX. EAX now holds (base_mem_kb + ext_mem_kb) in KB.
; Convert ext2_mem_mb to KB and add to the running total in EAX
movzx ebx, word [ext2_mem_mb] ; Load ext2_mem_mb (in MB) into EBX
mov ecx, 1024 ; Multiplier for MB to KB
imul ebx, ecx ; EBX = EBX * ECX (ext2_mem_mb * 1024) -> EBX now holds ext2_mem_kb
add eax, ebx ; Add ext2_mem_kb (now in EBX) to total KB in EAX
; Now convert total KB in EAX to MB for printing
mov edx, 0 ; Clear EDX for 32-bit division
mov ecx, 1024 ; Divisor
div ecx ; EAX = EAX / ECX (total KB / 1024). Result (MB) is in EAX.
call print_decimal ; Print the final value in EAX (total MB)
call print_M_suffix
ret
detect_cpu:
; --- CPU Vendor ---
mov si, cpu_vendor_label
call print_string
mov eax, 0
cpuid
mov [cpu_vendor_str+0], ebx
mov [cpu_vendor_str+4], edx
mov [cpu_vendor_str+8], ecx
mov si, cpu_vendor_str
call print_string
call print_newline
; --- CPU Brand String ---
mov si, cpu_desc_label
call print_string
mov eax, 0x80000002
cpuid
mov [cpu_type_str+0], eax
mov [cpu_type_str+4], ebx
mov [cpu_type_str+8], ecx
mov [cpu_type_str+12], edx
mov eax, 0x80000003
cpuid
mov [cpu_type_str+16], eax
mov [cpu_type_str+20], ebx
mov [cpu_type_str+24], ecx
mov [cpu_type_str+28], edx
mov eax, 0x80000004
cpuid
mov [cpu_type_str+32], eax
mov [cpu_type_str+36], ebx
mov [cpu_type_str+40], ecx
mov [cpu_type_str+44], edx
mov si, cpu_type_str
call print_string
call print_newline
ret
detect_drives:
mov si, hdd_label
call print_string
push es
mov ax, 0x0040
mov es, ax
; FIXED: Read only the BYTE at this address, not a word.
mov al, [es:0x0075] ; BIOS Data Area holds number of HDDs in one byte
mov ah, 0 ; Clear the upper byte of AX to prevent garbage
pop es
call print_decimal ; Print the correct value from AX
call print_newline
ret
detect_mouse:
mov si, mouse_label
call print_string
mov ax, 0
int 0x33
cmp ax, 0
je .no_mouse
mov si, mouse_found_str
call print_string
jmp .mouse_done
.no_mouse:
mov si, mouse_notfound_str
call print_string
.mouse_done:
call print_newline
ret
detect_serial_ports:
mov si, serial_count_label
call print_string
push es
mov ax, 0x0040
mov es, ax
mov cx, 0
mov si, 0
.loop:
mov dx, [es:si]
cmp dx, 0
je .next
inc cx
.next:
add si, 2
cmp si, 8
jne .loop
mov ax, cx
call print_decimal
call print_newline
mov si, serial_addr_label
call print_string
mov ax, [es:0]
pop es
call print_decimal
call print_newline
ret
detect_cpu_features:
mov si, features_label
call print_string
mov eax, 1
cpuid
mov [feature_flags_edx], edx
test edx, 1 << 0
jz .no_fpu
mov si, fpu_str
call print_string
.no_fpu:
test edx, 1 << 23
jz .no_mmx
mov si, mmx_str
call print_string
.no_mmx:
test edx, 1 << 25
jz .no_sse
mov si, sse_str
call print_string
.no_sse:
test edx, 1 << 26
jz .no_sse2
mov si, sse2_str
call print_string
.no_sse2:
call print_newline
ret
; ==================================================================
; HELPER & KERNEL SUBROUTINES
; ==================================================================
print_string:
mov ah, 0Eh ; AH+AL=AX. We use 0Eh to print characters in teletype mode
.repeat:
lodsb ; Load byte at DS:SI into AL and increment SI
cmp al, 0 ; Check if that character is null (end of string)
je .done
int 10h ; Print character in AL
jmp .repeat
.done:
ret
print_newline:
push ax ; Saves the current value of the AX register onto the stack
mov ah, 0Eh ; AH+AL=AX. We use 0Eh to print characters in teletype mode
mov al, 0Dh ; 0Dh is the ASCII value for "Carriage Return" (CR). Moves the cursor to the beginning of the current line.
int 10h ; Print character in AL
mov al, 0Ah ; 0Ah is the ASCII value for "Line Feed" (LF). Moves the cursor down one line.
int 10h
pop ax ; Restores the value of the AX register from the stack
ret ; Returns from the subroutine
print_k_suffix:
pusha ; Saves the current values of all general-purpose 16-bit registers onto the stack.
mov si, k_str ; Load the address of the 'k' string into SI
call print_string
call print_newline
popa ; Restores the values of all general-purpose 16-bit registers from the stack.
ret
print_M_suffix:
pusha
mov si, M_str
call print_string
call print_newline
popa
ret
read_string:
pusha
mov bx, di ; Need for backspace handling to prevent deleting characters before the buffer's beginning.
.read_loop:
mov ah, 00h ; BIOS function to read a character from the keyboard of BIOS Interrupt 16h
int 16h ; AL contains the ASCII code of the key pressed, and AH contains the scan code of the key.
cmp al, 0Dh ; 0Dh is the ASCII value for "Carriage Return" (Enter key)
je .done_reading
cmp al, 08h ; 08h is the ASCII value for "Backspace" key
je .backspace
mov [di], al ; Store the character in the buffer at DI
mov ah, 0Eh
int 10h ; Print the character on the screen
inc di ; Increment DI to point to the next position in the buffer
jmp .read_loop
.backspace:
cmp di, bx ; Check if DI is at the start of the buffer
je .read_loop
dec di ; Move DI back to the previous character
mov byte [di], 0 ; Clear the character from the buffer
mov ah, 0Eh ; AH+AL=AX. We use 0Eh to print characters in teletype mode
mov al, 08h ; 08h is the ASCII value for "Backspace" key
int 10h
mov al, ' '
int 10h
mov al, 08h ; After printing the space, the cursor has moved one position right.
int 10h ; We need to move it back to the left so that the next character typed appears correctly.
jmp .read_loop
.done_reading:
mov byte [di], 0 ; Null-terminate the string in the buffer
popa ; Restore the values of all general-purpose 16-bit registers from the stack.
ret
string_compare:
pusha
.loop:
mov al, [si]
mov ah, [di]
cmp al, ah
jne .notequal
cmp al, 0
je .equal
inc si
inc di
jmp .loop
.notequal:
popa
cmp ax, bx ; Force ZF=0 for 'not equal' condition
ret
.equal:
popa
cmp ax, ax ; Force ZF=1 for 'equal' condition
ret
print_decimal:
; This routine is for printing a 32-bit number from EAX
pusha
mov cx, 0 ; Counter for digits
mov ebx, 10 ; Divisor (for decimal conversion)
.div_loop:
xor edx, edx ; Clear EDX for 32-bit division (EDX:EAX / EBX)
div ebx ; EAX = EAX / EBX, EDX = EAX % EBX
push edx ; Push remainder (the digit) onto stack
inc cx ; Increment digit count
cmp eax, 0
jne .div_loop
.print_loop:
pop eax ; Pop a digit (remainder) into EAX
add al, '0' ; Convert digit to ASCII character
mov ah, 0Eh ; BIOS print character function
int 10h ; Print the character
loop .print_loop ; Decrement CX, loop if CX is not zero
popa
ret
clear_screen:
pusha
mov ah, 0x00 ; Set video mode function
mov al, 0x03 ; Text mode 80x25, 16 colors
int 10h ; Call BIOS interrupt
popa
ret
; ==================================================================
; KERNEL DATA
; ==================================================================
; We should initialize these data at the end of the file to avoid executing
; these non executable data as code.
welcome_string db 'Welcome to LuckyOS by Sachin!', 0
prompt_string db 'LuckyOS :) >> ', 0
unknown_cmd_string db 'Unknown command', 0
info_cmd db 'info', 0
help_cmd db 'help', 0
clear_cmd db 'clear', 0
help_menu_string db 'info - Hardware Information', 0Dh, 0Ah, 'clear - Clear Screen', 0Dh, 0Ah, 'help - Show this menu', 0Dh, 0Ah, 0
mem_base_label db 'Base Memory size: ', 0
mem_ext_label db 'Extended memory between (1M - 16M): ', 0
mem_ext2_label db 'Extended memory above 16M: ', 0
mem_total_label db 'Total memory: ', 0
cpu_vendor_label db 'CPU Vendor: ', 0
cpu_desc_label db 'CPU description: ', 0
hdd_label db 'Number of hard drives: ', 0
mouse_label db 'Mouse Status: ', 0
serial_count_label db 'Number of serial port: ', 0
serial_addr_label db 'Base I/O address for serial port 1: ', 0
features_label db 'CPU Features: ', 0
mouse_found_str db 'The Mouse Found', 0
mouse_notfound_str db 'Not Found', 0
not_supported_str db 'Not Supported', 0
k_str db 'k', 0
M_str db 'M', 0
fpu_str db 'FPU ', 0
mmx_str db 'MMX ', 0
sse_str db 'SSE ', 0
sse2_str db 'SSE2 ', 0
command_buffer times 64 db 0 ;Create a buffer for command input of 64 bytes
cpu_vendor_str times 13 db 0
cpu_type_str times 49 db 0
base_mem_kb dw 0
ext_mem_kb dw 0
ext2_mem_16k_blocks dw 0
ext2_mem_64k_blocks dw 0
ext2_mem_mb dw 0
feature_flags_edx dd 0
; ==================================================================
; END OF KERNEL
; ==================================================================