Interrupts dont work and I dont know why
This commit is contained in:
commit
dacf0315f3
|
@ -0,0 +1,56 @@
|
|||
# $@ = target file
|
||||
# $< = first dependency
|
||||
# $^ = all dependencies
|
||||
|
||||
GDB = gdb
|
||||
|
||||
C_FILES = $(shell find src/ -type f -name '*.c')
|
||||
CO_FILES = $(patsubst src/%.c, obj/%.o, $(C_FILES))
|
||||
ASM_FILES = $(shell find src/kernel/ -type f -name '*.asm')
|
||||
AO_FILES = $(patsubst src/kernel/%.asm, obj/kernel/%.o, $(ASM_FILES))
|
||||
ABIN_FILES = $(patsubst src/%.asm, bin/%.bin, $(ASM_FILES))
|
||||
|
||||
os-image.bin: bin/boot.bin bin/kernel.bin
|
||||
cat $^ > $@
|
||||
|
||||
bin/boot.bin: src/boot/boot.asm bin/kernel.bin .FORCE
|
||||
sed -i.orig "s@CH_REPLACE_BOOTSECTORCOUNT@$(shell ./getinblocks.py $(shell du -b "bin/kernel.bin" | cut -f 1))@g" src/boot/kernel.asm
|
||||
nasm -Isrc/boot/ $< -f bin -o $@
|
||||
mv src/boot/kernel.asm.orig src/boot/kernel.asm
|
||||
|
||||
.FORCE:
|
||||
|
||||
bin/kernel.bin: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
|
||||
|
||||
kernel.elf: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
|
||||
i386-elf-ld -o $@ -Ttext 0x1000 $^
|
||||
|
||||
run: clean os-image.bin
|
||||
qemu-system-x86_64 -hdd os-image.bin
|
||||
|
||||
debug: clean os-image.bin kernel.elf
|
||||
qemu-system-x86_64 -s -S -hdd os-image.bin &
|
||||
${GDB} os-image.bin -ex "symbol-file kernel.elf" -ex "target remote localhost:1234"
|
||||
|
||||
|
||||
|
||||
obj/%.o: src/%.c
|
||||
mkdir -p "$(@D)"
|
||||
i386-elf-gcc -g -ffreestanding -c $< -o $@
|
||||
|
||||
obj/%.o: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f elf $< -o $@
|
||||
|
||||
bin/%.bin: src/%.asm
|
||||
mkdir -p "$(@D)"
|
||||
nasm -f bin $< -o $@
|
||||
|
||||
clean:
|
||||
find obj -type f -name '*.o' -exec rm {} +
|
||||
find obj -type f -name '*.bin' -exec rm {} +
|
||||
find bin -type f -name '*.o' -exec rm {} +
|
||||
find bin -type f -name '*.bin' -exec rm {} +
|
||||
find . -type f -name '*.dis' -exec rm {} +
|
||||
rm -f kernel.elf
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
import sys, math
|
||||
intg = int(sys.argv[1])
|
||||
print(int(math.ceil(intg/512)), end='')
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,28 @@
|
|||
[org 0x7c00]
|
||||
|
||||
mov bx, HELLO
|
||||
call print
|
||||
call print_nl
|
||||
|
||||
mov bx, GOODBYE
|
||||
call print
|
||||
|
||||
call print_nl
|
||||
|
||||
mov dx, 0x12fe
|
||||
call print_hex
|
||||
|
||||
jmp $
|
||||
|
||||
%include "print.asm"
|
||||
%include "print_hex.asm"
|
||||
|
||||
; data
|
||||
HELLO:
|
||||
db 'Hello, world!', 0
|
||||
|
||||
GOODBYE:
|
||||
db 'Bye bye!', 0
|
||||
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,40 @@
|
|||
; load 'dh' sectors from drive 'dl' into ES:BX
|
||||
disk_load:
|
||||
pusha
|
||||
push dx ; save dx to stack for later use, as it needs to be overwritten
|
||||
|
||||
mov ah, 0x02 ; ah: int 0x13 function. 0x02 = 'read'
|
||||
mov al, dh ; al: number of sectors to read (0x01 .. 0x80)
|
||||
mov cl, 0x02 ; cl: sector (0x01 .. 0x11). 0x01 is boot sector, 0x02 is first 'avaliable' sector
|
||||
mov ch, 0x00 ; ch: cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
|
||||
; dl: drive number. caller sets it as param and gets it from bios
|
||||
; 0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2
|
||||
mov dh, 0x00 ; dh: head number (0x0 .. 0xF)
|
||||
|
||||
; [es:bx] pointer to buf where data is stored
|
||||
; caller sets it up, and is standard location for int 13h
|
||||
int 13h
|
||||
jc disk_error ; if error (in carry)
|
||||
|
||||
pop dx
|
||||
cmp al, dh ; al is # of sectors read. compare it
|
||||
jne sectors_error
|
||||
popa
|
||||
ret
|
||||
|
||||
disk_error:
|
||||
mov bx, DISK_ERROR
|
||||
call print
|
||||
call print_nl
|
||||
mov dh, ah ; ah = error code, dl = disk drive that caused error
|
||||
call print_hex
|
||||
|
||||
sectors_error:
|
||||
mov bx, SECTORS_ERROR
|
||||
call print
|
||||
|
||||
disk_loop:
|
||||
jmp $
|
||||
|
||||
DISK_ERROR: db "Disk read error", 0
|
||||
SECTORS_ERROR: db "Incorrect number of sectors read", 0
|
|
@ -0,0 +1,28 @@
|
|||
[org 0x7c00]
|
||||
mov bp, 0x8000 ; set stack somewhere far away
|
||||
mov sp, bp
|
||||
|
||||
mov bx, 0x9000 ; es:bx = 0x0000:0x9000 = 0x09000
|
||||
mov dh, 2 ; read 2 sectors
|
||||
; bios sets dl for disk number
|
||||
call disk_load
|
||||
|
||||
mov dx, [0x9000] ; get first loaded word, 0xdada
|
||||
call print_hex
|
||||
call print_nl
|
||||
|
||||
mov dx, [0x9000 + 512] ; first word from second loaded sector, 0xface
|
||||
call print_hex
|
||||
|
||||
jmp $
|
||||
|
||||
%include "print.asm"
|
||||
%include "print_hex.asm"
|
||||
%include "disk.asm"
|
||||
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
||||
|
||||
; boot sector passed, now its sector 2
|
||||
times 256 dw 0xdada ; sector 2
|
||||
times 256 dw 0xface ; sector 3
|
|
@ -0,0 +1,26 @@
|
|||
mov ah, 0x0e
|
||||
|
||||
mov al, [the_secret]
|
||||
int 0x10 ; shouldnt work
|
||||
|
||||
mov bx, 0x7c0 ; segment is automatically << 4
|
||||
mov ds, bx ; set data segment offset to 0x7c0
|
||||
; all memory references will be offset by ds implicitly
|
||||
mov al, [the_secret]
|
||||
int 0x10
|
||||
|
||||
mov al, [es:the_secret]
|
||||
int 0x10
|
||||
|
||||
mov bx, 0x7c0
|
||||
mov es, bx
|
||||
mov al, [es:the_secret]
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
the_secret:
|
||||
db "X"
|
||||
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,31 @@
|
|||
gdt_start: ; use labels to compute sizes and jumps
|
||||
; gdt starts with 8 byte null
|
||||
dd 0x0
|
||||
dd 0x0
|
||||
|
||||
; GDT for code segment, base = 0x00000000, length = 0xfffff
|
||||
gdt_code:
|
||||
dw 0xffff ; segment length
|
||||
dw 0x0 ; segment base
|
||||
db 0x0 ; segment base
|
||||
db 10011010b ; flags
|
||||
db 11001111b ; flags + segment length
|
||||
db 0x0 ; segment base
|
||||
|
||||
; GDT for data segment
|
||||
gdt_data:
|
||||
dw 0xffff
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 10010010b
|
||||
db 11001111b
|
||||
db 0x0
|
||||
|
||||
gdt_end:
|
||||
|
||||
gdt_descriptor:
|
||||
dw gdt_end - gdt_start - 1 ; size, always 1 less than what it actually is
|
||||
dd gdt_start ; address
|
||||
|
||||
CODE_SEG equ gdt_code - gdt_start
|
||||
DATA_SEG equ gdt_data - gdt_start
|
|
@ -0,0 +1,22 @@
|
|||
[bits 16]
|
||||
enter_protected:
|
||||
cli ; Disable interrupts
|
||||
lgdt [gdt_descriptor] ; load the GDT
|
||||
mov eax, cr0
|
||||
or eax, 0x1 ; set 32-bit mode bit
|
||||
mov cr0, eax
|
||||
jmp CODE_SEG:init_protected ; far jump into a different segment
|
||||
|
||||
[bits 32]
|
||||
init_protected: ; now in 32bit
|
||||
mov ax, DATA_SEG ; update segment registers
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
mov ebp, 0x90000 ; update stack to top of free space
|
||||
mov esp, ebp
|
||||
|
||||
call BEGIN_PROTECTED ; call known label with useful code
|
|
@ -0,0 +1,27 @@
|
|||
[org 0x7c00] ; bootloader offset
|
||||
mov bp, 0x9000 ; set stack
|
||||
mov sp, bp
|
||||
|
||||
mov bx, MSG_REAL_MODE
|
||||
call print ; will be written after bios messages
|
||||
|
||||
call enter_protected
|
||||
jmp $ ; will never really be executed
|
||||
|
||||
%include "print.asm"
|
||||
%include "32bit_gdt.asm"
|
||||
%include "32bit_print.asm"
|
||||
%include "32bit_jump.asm"
|
||||
|
||||
[bits 32]
|
||||
BEGIN_PROTECTED: ; 32bit entry
|
||||
mov ebx, MSG_PROT_MODE
|
||||
call print_string_pm ; Will be written in top left
|
||||
jmp $
|
||||
|
||||
MSG_REAL_MODE db "Welcome! Started in 16-bit protected mode"
|
||||
MSG_PROT_MODE db "Hello, world! 32-bit mode initialized successfully"
|
||||
|
||||
; bootsector
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,26 @@
|
|||
[bits 32]
|
||||
|
||||
; defining constants
|
||||
VIDEO_MEMORY equ 0xb8000
|
||||
WHITE_ON_BLACK equ 0x0f ; color byte
|
||||
|
||||
print_string_pm:
|
||||
pusha
|
||||
mov edx, VIDEO_MEMORY
|
||||
|
||||
print_string_pm_loop:
|
||||
mov al, [ebx] ; [ebx] is address of char
|
||||
mov ah, WHITE_ON_BLACK
|
||||
|
||||
cmp al, 0 ; is end of string?
|
||||
je print_string_pm_done
|
||||
|
||||
mov [edx], ax ; store char + attribute in video memory
|
||||
add ebx, 1 ; next char
|
||||
add edx, 2 ; next video memory position
|
||||
|
||||
jmp print_string_pm_loop
|
||||
|
||||
print_string_pm_done:
|
||||
popa
|
||||
ret
|
|
@ -0,0 +1,3 @@
|
|||
int my_function() {
|
||||
return 0xbaba;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
void caller() {
|
||||
my_func(0xdede);
|
||||
}
|
||||
|
||||
int my_func(int arg) {
|
||||
return arg;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
loop:
|
||||
jmp loop
|
||||
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,18 @@
|
|||
mov ah, 0x0e ; enable TTY
|
||||
|
||||
mov al, 'H'
|
||||
int 0x10
|
||||
mov al, 'e'
|
||||
int 0x10
|
||||
mov al, 'l'
|
||||
int 0x10
|
||||
int 0x10
|
||||
mov al, 'o'
|
||||
int 0x10
|
||||
mov al, '!'
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,27 @@
|
|||
mov ah, 0x0e ; enable TTY
|
||||
|
||||
mov al, "1"
|
||||
int 0x10
|
||||
mov al, the_secret
|
||||
int 0x10
|
||||
|
||||
mov al, "2"
|
||||
int 0x10
|
||||
mov al, [the_secret]
|
||||
int 0x10
|
||||
|
||||
mov al, "3"
|
||||
int 0x10
|
||||
mov bx, the_secret
|
||||
add bx, 0x7c00
|
||||
mov al, [bx]
|
||||
int 0x10
|
||||
|
||||
jmp $ ; infinite loop
|
||||
|
||||
the_secret:
|
||||
; store 0x58 'X' right before zeropad
|
||||
db "X"
|
||||
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,38 @@
|
|||
mov ah, 0x0e ; tty mode
|
||||
|
||||
mov bp, 0x8000 ; far away from 0x7c00, want to avoid overwriting ourself
|
||||
mov sp, bp ; if stack empty, sp points to bp
|
||||
|
||||
push 'A'
|
||||
push 'B'
|
||||
push 'C'
|
||||
|
||||
; stack grows downwards
|
||||
mov al, [0x7ffe] ; 0x8000 - 2
|
||||
int 0x10
|
||||
|
||||
; you can only access stack top now
|
||||
mov al, [0x8000]
|
||||
int 0x10
|
||||
|
||||
; recover chars with pop
|
||||
; you can onoly pop words, so you need an aux register to manipulate the lower byte
|
||||
pop bx
|
||||
mov al, bl
|
||||
int 0x10
|
||||
|
||||
pop bx
|
||||
mov al, bl
|
||||
int 0x10
|
||||
|
||||
pop bx
|
||||
mov al, bl
|
||||
int 0x10
|
||||
|
||||
; pop'd stack is garbage now
|
||||
mov al, [0x8000]
|
||||
int 0x10
|
||||
|
||||
jmp $
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
print:
|
||||
pusha
|
||||
|
||||
; logic being implemented here:
|
||||
; while ( string[i] != 0 ) { print string[i]; i++ }
|
||||
|
||||
start:
|
||||
mov al, [bx]
|
||||
cmp al, 0 ; check if al (byte we are printing) is a 0 (null byte)
|
||||
je done ; if so, jump to done
|
||||
|
||||
; print with BIOS help
|
||||
mov ah, 0x0e
|
||||
int 0x10 ; char already in al
|
||||
|
||||
add bx, 1 ; increment pointer
|
||||
jmp start ; repeat
|
||||
|
||||
done:
|
||||
popa
|
||||
ret
|
||||
|
||||
print_nl:
|
||||
pusha
|
||||
|
||||
mov ah, 0x0e
|
||||
mov al, 0x0a ; newline char
|
||||
int 0x10
|
||||
mov al, 0x0d ; carriage return
|
||||
int 0x10
|
||||
|
||||
popa
|
||||
ret
|
|
@ -0,0 +1,38 @@
|
|||
; data in dx
|
||||
print_hex:
|
||||
pusha
|
||||
|
||||
mov cx, 0 ; index var
|
||||
|
||||
hex_loop:
|
||||
cmp cx, 4 ; loop 4 times
|
||||
je end
|
||||
|
||||
; 1) convert last char of 'dx' to ascii
|
||||
mov ax, dx ; ax is working register
|
||||
and ax, 0x000f ; 0x1234 -> 0x0004
|
||||
add al, 0x30 ; add 0x30 to N to convert it to ascii "n"
|
||||
cmp al, 0x39 ; if > 9, add extra 8 to represent a-f
|
||||
jle step2
|
||||
add al, 7 ; A is ascii 64 instead of 58, 65-58 = 7
|
||||
|
||||
step2:
|
||||
; 2) get correct pos of string to place char
|
||||
; bx <- base address + string length - index
|
||||
mov bx, HEX_OUT + 5
|
||||
sub bx, cx ; cx: index
|
||||
mov [bx], al ; copy ascii char on al to pos pointed by bx
|
||||
ror dx, 4 ; 1234 - 4123 - 3412 - 2341 - 1234
|
||||
|
||||
add cx, 1
|
||||
jmp hex_loop
|
||||
|
||||
end:
|
||||
mov bx, HEX_OUT
|
||||
call print
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
HEX_OUT:
|
||||
db '0x0000', 0 ; reserve memory for string
|
Binary file not shown.
|
@ -0,0 +1,39 @@
|
|||
[org 0x7c00]
|
||||
KERNEL_OFFSET equ 0x1000 ; Same one used while linking!
|
||||
|
||||
mov [BOOT_DRIVE], dl ; BIOS sets boot drive to 'dl' for us
|
||||
mov bp, 0x9000
|
||||
mov sp, bp
|
||||
|
||||
mov bx, MSG_REAL_MODE
|
||||
call print
|
||||
call print_nl
|
||||
|
||||
call load_kernel
|
||||
call enable_protected
|
||||
|
||||
jmp $ ; never executed
|
||||
|
||||
%include "output/print.asm"
|
||||
%include "output/print_hex.asm"
|
||||
%include "disk/disk.asm"
|
||||
%include "protected/gdt.asm"
|
||||
%include "output/vga-print.asm"
|
||||
%include "protected/protected-switch.asm"
|
||||
%include "kernel.asm"
|
||||
|
||||
[bits 32]
|
||||
BEGIN_PROTECTED:
|
||||
mov ebx, MSG_PROT_MODE
|
||||
call print_string_pm
|
||||
|
||||
call KERNEL_OFFSET ; give control to kernel
|
||||
jmp $ ; infinite loop if kernel returns control to us
|
||||
|
||||
BOOT_DRIVE db 0
|
||||
MSG_REAL_MODE db "llb: started, preparing protected mode initialization", 0
|
||||
MSG_PROT_MODE db "llb: loaded protected mode successfully, jumping to llb2", 0
|
||||
MSG_LOAD_KERNEL db "llb: loading kernel into memory at 0x1000", 0
|
||||
|
||||
times 510 - ($-$$) db 0
|
||||
dw 0xaa55
|
|
@ -0,0 +1,40 @@
|
|||
; load 'dh' sectors from drive 'dl' into ES:BX
|
||||
disk_load:
|
||||
pusha
|
||||
push dx ; save dx to stack for later use, as it needs to be overwritten
|
||||
|
||||
mov ah, 0x02 ; ah: int 0x13 function. 0x02 = 'read'
|
||||
mov al, dh ; al: number of sectors to read (0x01 .. 0x80)
|
||||
mov cl, 0x02 ; cl: sector (0x01 .. 0x11). 0x01 is boot sector, 0x02 is first 'avaliable' sector
|
||||
mov ch, 0x00 ; ch: cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
|
||||
; dl: drive number. caller sets it as param and gets it from bios
|
||||
; 0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2
|
||||
mov dh, 0x00 ; dh: head number (0x0 .. 0xF)
|
||||
|
||||
; [es:bx] pointer to buf where data is stored
|
||||
; caller sets it up, and is standard location for int 13h
|
||||
int 13h
|
||||
jc disk_error ; if error (in carry)
|
||||
|
||||
pop dx
|
||||
cmp al, dh ; al is # of sectors read. compare it
|
||||
jne sectors_error
|
||||
popa
|
||||
ret
|
||||
|
||||
disk_error:
|
||||
mov bx, DISK_ERROR
|
||||
call print
|
||||
call print_nl
|
||||
mov dh, ah ; ah = error code, dl = disk drive that caused error
|
||||
call print_hex
|
||||
|
||||
sectors_error:
|
||||
mov bx, SECTORS_ERROR
|
||||
call print
|
||||
|
||||
disk_loop:
|
||||
jmp $
|
||||
|
||||
DISK_ERROR: db "Disk read error", 0
|
||||
SECTORS_ERROR: db "Incorrect number of sectors read", 0
|
|
@ -0,0 +1,11 @@
|
|||
[bits 16]
|
||||
load_kernel:
|
||||
mov bx, MSG_LOAD_KERNEL
|
||||
call print
|
||||
call print_nl
|
||||
|
||||
mov bx, KERNEL_OFFSET ; Read from disk and store at 0x1000
|
||||
mov dh, CH_REPLACE_BOOTSECTORCOUNT ; Populated with kernel sector count at build (see makefile)
|
||||
mov dl, [BOOT_DRIVE]
|
||||
call disk_load
|
||||
ret
|
|
@ -0,0 +1,33 @@
|
|||
print:
|
||||
pusha
|
||||
|
||||
; logic being implemented here:
|
||||
; while ( string[i] != 0 ) { print string[i]; i++ }
|
||||
|
||||
start:
|
||||
mov al, [bx]
|
||||
cmp al, 0 ; check if al (byte we are printing) is a 0 (null byte)
|
||||
je done ; if so, jump to done
|
||||
|
||||
; print with BIOS help
|
||||
mov ah, 0x0e
|
||||
int 0x10 ; char already in al
|
||||
|
||||
add bx, 1 ; increment pointer
|
||||
jmp start ; repeat
|
||||
|
||||
done:
|
||||
popa
|
||||
ret
|
||||
|
||||
print_nl:
|
||||
pusha
|
||||
|
||||
mov ah, 0x0e
|
||||
mov al, 0x0a ; newline char
|
||||
int 0x10
|
||||
mov al, 0x0d ; carriage return
|
||||
int 0x10
|
||||
|
||||
popa
|
||||
ret
|
|
@ -0,0 +1,38 @@
|
|||
; data in dx
|
||||
print_hex:
|
||||
pusha
|
||||
|
||||
mov cx, 0 ; index var
|
||||
|
||||
hex_loop:
|
||||
cmp cx, 4 ; loop 4 times
|
||||
je end
|
||||
|
||||
; 1) convert last char of 'dx' to ascii
|
||||
mov ax, dx ; ax is working register
|
||||
and ax, 0x000f ; 0x1234 -> 0x0004
|
||||
add al, 0x30 ; add 0x30 to N to convert it to ascii "n"
|
||||
cmp al, 0x39 ; if > 9, add extra 8 to represent a-f
|
||||
jle step2
|
||||
add al, 7 ; A is ascii 64 instead of 58, 65-58 = 7
|
||||
|
||||
step2:
|
||||
; 2) get correct pos of string to place char
|
||||
; bx <- base address + string length - index
|
||||
mov bx, HEX_OUT + 5
|
||||
sub bx, cx ; cx: index
|
||||
mov [bx], al ; copy ascii char on al to pos pointed by bx
|
||||
ror dx, 4 ; 1234 - 4123 - 3412 - 2341 - 1234
|
||||
|
||||
add cx, 1
|
||||
jmp hex_loop
|
||||
|
||||
end:
|
||||
mov bx, HEX_OUT
|
||||
call print
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
HEX_OUT:
|
||||
db '0x0000', 0 ; reserve memory for string
|
|
@ -0,0 +1,26 @@
|
|||
[bits 32]
|
||||
|
||||
; defining constants
|
||||
VIDEO_MEMORY equ 0xb8000
|
||||
WHITE_ON_BLACK equ 0x0f ; color byte
|
||||
|
||||
print_string_pm:
|
||||
pusha
|
||||
mov edx, VIDEO_MEMORY
|
||||
|
||||
print_string_pm_loop:
|
||||
mov al, [ebx] ; [ebx] is address of char
|
||||
mov ah, WHITE_ON_BLACK
|
||||
|
||||
cmp al, 0 ; is end of string?
|
||||
je print_string_pm_done
|
||||
|
||||
mov [edx], ax ; store char + attribute in video memory
|
||||
add ebx, 1 ; next char
|
||||
add edx, 2 ; next video memory position
|
||||
|
||||
jmp print_string_pm_loop
|
||||
|
||||
print_string_pm_done:
|
||||
popa
|
||||
ret
|
|
@ -0,0 +1,31 @@
|
|||
gdt_start: ; use labels to compute sizes and jumps
|
||||
; gdt starts with 8 byte null
|
||||
dd 0x0
|
||||
dd 0x0
|
||||
|
||||
; GDT for code segment, base = 0x00000000, length = 0xfffff
|
||||
gdt_code:
|
||||
dw 0xffff ; segment length
|
||||
dw 0x0 ; segment base
|
||||
db 0x0 ; segment base
|
||||
db 10011010b ; flags
|
||||
db 11001111b ; flags + segment length
|
||||
db 0x0 ; segment base
|
||||
|
||||
; GDT for data segment
|
||||
gdt_data:
|
||||
dw 0xffff
|
||||
dw 0x0
|
||||
db 0x0
|
||||
db 10010010b
|
||||
db 11001111b
|
||||
db 0x0
|
||||
|
||||
gdt_end:
|
||||
|
||||
gdt_descriptor:
|
||||
dw gdt_end - gdt_start - 1 ; size, always 1 less than what it actually is
|
||||
dd gdt_start ; address
|
||||
|
||||
CODE_SEG equ gdt_code - gdt_start
|
||||
DATA_SEG equ gdt_data - gdt_start
|
|
@ -0,0 +1,24 @@
|
|||
[bits 16]
|
||||
enable_protected:
|
||||
cli ; Disable interrupts
|
||||
lgdt [gdt_descriptor] ; load the GDT
|
||||
mov eax, cr0
|
||||
or eax, 0x1 ; set 32-bit mode bit
|
||||
mov cr0, eax
|
||||
jmp CODE_SEG:init_protected ; far jump into a different segment
|
||||
|
||||
[bits 32]
|
||||
init_protected: ; now in 32bit
|
||||
mov ax, DATA_SEG ; update segment registers
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; wipe registers clean
|
||||
|
||||
mov ebp, 0x90000 ; update stack to top of free space
|
||||
mov esp, ebp
|
||||
|
||||
call BEGIN_PROTECTED ; call known label with useful code
|
|
@ -0,0 +1,4 @@
|
|||
[bits 32]
|
||||
[extern main] ; define callpoint, must have same name as kernel.c entrypoint
|
||||
call main ; jump to fun, linker will figure out where it is
|
||||
jmp $
|
|
@ -0,0 +1,65 @@
|
|||
#include "./platform/drivers/ports.h"
|
||||
#include "print.h"
|
||||
#include "./platform/types.h"
|
||||
#include "./platform/interrupts/idt.h"
|
||||
#include "./platform/interrupts/isr.h"
|
||||
|
||||
void dummy_test_entrypoint() {}
|
||||
|
||||
void kernel_welcome() {
|
||||
print_str("Welcome to ");
|
||||
print_set_color(PRINT_COLOR_CYAN, PRINT_COLOR_BLACK);
|
||||
print_str("Shade");
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str("!\n");
|
||||
|
||||
print_str("shadeOS kernel version ");
|
||||
|
||||
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
|
||||
print_str("0.2.2");
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_newline();
|
||||
|
||||
print_str("Running on ");
|
||||
|
||||
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
|
||||
print_str("shade-development");
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
|
||||
print_newline();
|
||||
}
|
||||
|
||||
// kMain
|
||||
void main() {
|
||||
// Initialize screen buffer
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
clear_all(); // Clear screen
|
||||
set_cursor_pos(0, 0); // Set cursor position
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); // Set print color
|
||||
|
||||
// welcome messages
|
||||
kernel_msg_ok("Initialized display successfully\n");
|
||||
kernel_welcome();
|
||||
|
||||
print_str("Copyright (c) e3team 2022. All rights reserved.\n");
|
||||
print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
|
||||
print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
|
||||
|
||||
print_str("Initializing interrupts...\n");
|
||||
isr_setup();
|
||||
kernel_msg_ok("isr setup done\n");
|
||||
|
||||
// Test interrupts
|
||||
__asm__ __volatile__("int $2");
|
||||
kernel_msg_ok("int 2 not failed");
|
||||
__asm__ __volatile__("int $3");
|
||||
__asm__ __volatile__("int $2");
|
||||
__asm__ __volatile__("int $3");
|
||||
__asm__ __volatile__("int $2");
|
||||
__asm__ __volatile__("int $3");
|
||||
|
||||
kernel_msg_ok("interrupt test completed\n");
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Read 1 byte from specified port
|
||||
*/
|
||||
unsigned char port_byte_in(unsigned short port) {
|
||||
unsigned char result;
|
||||
// source and dest are backwards.
|
||||
// "=a (result)" set the C variable to the value of register e'a'x
|
||||
// '"d" (port) map the C variable port into e'd'x register
|
||||
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
|
||||
}
|
||||
|
||||
void port_byte_out(unsigned short port, unsigned char data) {
|
||||
// both regs are C vars, nothing is returned, so no '=' in asm syntax
|
||||
// comma because two vars in input area and none in return area
|
||||
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
unsigned short port_word_in(unsigned short port) {
|
||||
unsigned short result;
|
||||
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
void port_word_out(unsigned short port, unsigned short data) {
|
||||
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
unsigned char port_byte_in(unsigned short port);
|
||||
void port_byte_out(unsigned short port, unsigned char data);
|
||||
unsigned short port_word_in(unsigned short port);
|
||||
void port_word_out(unsigned short port, unsigned short data);
|
|
@ -0,0 +1,20 @@
|
|||
#include "idt.h"
|
||||
#include "../../util.h"
|
||||
|
||||
idt_gate_t idt[IDT_ENTRIES];
|
||||
idt_pointer_t idt_ptr;
|
||||
|
||||
void idt_set_gate(int n, u32 handler_addr) {
|
||||
idt[n].low_offset = low16(handler_addr);
|
||||
idt[n].sel = KERNEL_CS;
|
||||
idt[n].reserved = 0;
|
||||
idt[n].flags = 0x8E;
|
||||
idt[n].high_offset = high16(handler_addr);
|
||||
}
|
||||
|
||||
void idt_set() {
|
||||
idt_ptr.base = (u32) &idt;
|
||||
idt_ptr.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
|
||||
/* Don't make the mistake of loading &idt -- always load &idt_reg */
|
||||
__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_ptr));
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
#define KERNEL_CS 0x08
|
||||
#define IDT_ENTRIES 256
|
||||
|
||||
// An entry in the IDT
|
||||
typedef struct {
|
||||
u16 low_offset; // Low 16 bits of handler address
|
||||
u16 sel; // Kernel code segment selector
|
||||
u8 reserved; // Always zero
|
||||
u8 flags; // x xx x xxxx, Present, ring, type, 1110 = "32bit int gate"
|
||||
u16 high_offset; // High 16 bits of handler address
|
||||
} __attribute__((packed)) idt_gate_t;
|
||||
|
||||
// The IDT itself
|
||||
typedef struct {
|
||||
u16 limit;
|
||||
u32 base;
|
||||
} __attribute__((packed)) idt_pointer_t;
|
||||
|
||||
void idt_set_gate(int n, u32 handler_addr);
|
||||
void idt_set();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,286 @@
|
|||
; in isr.c
|
||||
[extern isr_handler]
|
||||
|
||||
isr_common_stub:
|
||||
; Save CPU state
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
mov ax, 0x10 ; kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; Call C handler
|
||||
call isr_handler
|
||||
|
||||
; Restore CPU state
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
|
||||
sti
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
|
||||
; We don't get information about which interrupt was caller
|
||||
; when the handler is run, so we will need to have a different handler
|
||||
; for every interrupt.
|
||||
; Furthermore, some interrupts push an error code onto the stack but others
|
||||
; don't, so we will push a dummy error code for those which don't, so that
|
||||
; we have a consistent stack for all of them.
|
||||
|
||||
; First make the ISRs global
|
||||
global isr00
|
||||
global isr01
|
||||
global isr02
|
||||
global isr03
|
||||
global isr04
|
||||
global isr05
|
||||
global isr06
|
||||
global isr07
|
||||
global isr08
|
||||
global isr09
|
||||
global isr10
|
||||
global isr11
|
||||
global isr12
|
||||
global isr13
|
||||
global isr14
|
||||
global isr15
|
||||
global isr16
|
||||
global isr17
|
||||
global isr18
|
||||
global isr19
|
||||
global isr20
|
||||
global isr21
|
||||
global isr22
|
||||
global isr23
|
||||
global isr24
|
||||
global isr25
|
||||
global isr26
|
||||
global isr27
|
||||
global isr28
|
||||
global isr29
|
||||
global isr30
|
||||
global isr31
|
||||
|
||||
; 0: Divide By Zero Exception
|
||||
isr00:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 0
|
||||
jmp isr_common_stub
|
||||
|
||||
; 1: Debug Exception
|
||||
isr01:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 1
|
||||
jmp isr_common_stub
|
||||
|
||||
; 2: Non Maskable Interrupt Exception
|
||||
isr02:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 2
|
||||
jmp isr_common_stub
|
||||
|
||||
; 3: Int 3 Exception
|
||||
isr03:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 3
|
||||
jmp isr_common_stub
|
||||
|
||||
; 4: INTO Exception
|
||||
isr04:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 4
|
||||
jmp isr_common_stub
|
||||
|
||||
; 5: Out of Bounds Exception
|
||||
isr05:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 5
|
||||
jmp isr_common_stub
|
||||
|
||||
; 6: Invalid Opcode Exception
|
||||
isr06:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 6
|
||||
jmp isr_common_stub
|
||||
|
||||
; 7: Coprocessor Not Available Exception
|
||||
isr07:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 7
|
||||
jmp isr_common_stub
|
||||
|
||||
; 8: Double Fault Exception (With Error Code!)
|
||||
isr08:
|
||||
cli
|
||||
push byte 8
|
||||
jmp isr_common_stub
|
||||
|
||||
; 9: Coprocessor Segment Overrun Exception
|
||||
isr09:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 9
|
||||
jmp isr_common_stub
|
||||
|
||||
; 10: Bad TSS Exception (With Error Code!)
|
||||
isr10:
|
||||
cli
|
||||
push byte 10
|
||||
jmp isr_common_stub
|
||||
|
||||
; 11: Segment Not Present Exception (With Error Code!)
|
||||
isr11:
|
||||
cli
|
||||
push byte 11
|
||||
jmp isr_common_stub
|
||||
|
||||
; 12: Stack Fault Exception (With Error Code!)
|
||||
isr12:
|
||||
cli
|
||||
push byte 12
|
||||
jmp isr_common_stub
|
||||
|
||||
; 13: General Protection Fault Exception (With Error Code!)
|
||||
isr13:
|
||||
cli
|
||||
push byte 13
|
||||
jmp isr_common_stub
|
||||
|
||||
; 14: Page Fault Exception (With Error Code!)
|
||||
isr14:
|
||||
cli
|
||||
push byte 14
|
||||
jmp isr_common_stub
|
||||
|
||||
; 15: Reserved Exception
|
||||
isr15:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 15
|
||||
jmp isr_common_stub
|
||||
|
||||
; 16: Floating Point Exception
|
||||
isr16:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 16
|
||||
jmp isr_common_stub
|
||||
|
||||
; 17: Alignment Check Exception
|
||||
isr17:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 17
|
||||
jmp isr_common_stub
|
||||
|
||||
; 18: Machine Check Exception
|
||||
isr18:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 18
|
||||
jmp isr_common_stub
|
||||
|
||||
; 19: Reserved
|
||||
isr19:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 19
|
||||
jmp isr_common_stub
|
||||
|
||||
; 20: Reserved
|
||||
isr20:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 20
|
||||
jmp isr_common_stub
|
||||
|
||||
; 21: Reserved
|
||||
isr21:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 21
|
||||
jmp isr_common_stub
|
||||
|
||||
; 22: Reserved
|
||||
isr22:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 22
|
||||
jmp isr_common_stub
|
||||
|
||||
; 23: Reserved
|
||||
isr23:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 23
|
||||
jmp isr_common_stub
|
||||
|
||||
; 24: Reserved
|
||||
isr24:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 24
|
||||
jmp isr_common_stub
|
||||
|
||||
; 25: Reserved
|
||||
isr25:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 25
|
||||
jmp isr_common_stub
|
||||
|
||||
; 26: Reserved
|
||||
isr26:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 26
|
||||
jmp isr_common_stub
|
||||
|
||||
; 27: Reserved
|
||||
isr27:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 27
|
||||
jmp isr_common_stub
|
||||
|
||||
; 28: Reserved
|
||||
isr28:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 28
|
||||
jmp isr_common_stub
|
||||
|
||||
; 29: Reserved
|
||||
isr29:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 29
|
||||
jmp isr_common_stub
|
||||
|
||||
; 30: Reserved
|
||||
isr30:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 30
|
||||
jmp isr_common_stub
|
||||
|
||||
; 31: Reserved
|
||||
isr31:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 31
|
||||
jmp isr_common_stub
|
|
@ -0,0 +1,89 @@
|
|||
#include "isr.h"
|
||||
#include "idt.h"
|
||||
#include "../../print.h"
|
||||
#include "../../util.h"
|
||||
|
||||
void isr_setup() {
|
||||
idt_set_gate(0, (u32)isr00);
|
||||
idt_set_gate(1, (u32)isr01);
|
||||
idt_set_gate(2, (u32)isr02);
|
||||
idt_set_gate(3, (u32)isr03);
|
||||
idt_set_gate(4, (u32)isr04);
|
||||
idt_set_gate(5, (u32)isr05);
|
||||
idt_set_gate(6, (u32)isr06);
|
||||
idt_set_gate(7, (u32)isr07);
|
||||
idt_set_gate(8, (u32)isr08);
|
||||
idt_set_gate(9, (u32)isr09);
|
||||
idt_set_gate(10, (u32)isr10);
|
||||
idt_set_gate(11, (u32)isr11);
|
||||
idt_set_gate(12, (u32)isr12);
|
||||
idt_set_gate(13, (u32)isr13);
|
||||
idt_set_gate(14, (u32)isr14);
|
||||
idt_set_gate(15, (u32)isr15);
|
||||
idt_set_gate(16, (u32)isr16);
|
||||
idt_set_gate(17, (u32)isr17);
|
||||
idt_set_gate(18, (u32)isr18);
|
||||
idt_set_gate(19, (u32)isr19);
|
||||
idt_set_gate(20, (u32)isr20);
|
||||
idt_set_gate(21, (u32)isr21);
|
||||
idt_set_gate(22, (u32)isr22);
|
||||
idt_set_gate(23, (u32)isr23);
|
||||
idt_set_gate(24, (u32)isr24);
|
||||
idt_set_gate(25, (u32)isr25);
|
||||
idt_set_gate(26, (u32)isr26);
|
||||
idt_set_gate(27, (u32)isr27);
|
||||
idt_set_gate(28, (u32)isr28);
|
||||
idt_set_gate(29, (u32)isr29);
|
||||
idt_set_gate(30, (u32)isr30);
|
||||
idt_set_gate(31, (u32)isr31);
|
||||
|
||||
idt_set();
|
||||
}
|
||||
|
||||
char *exception_messages[] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
void isr_handler(registers_t r) {
|
||||
print_str("int: ");
|
||||
char s[3];
|
||||
int_to_ascii(r.int_no, s);
|
||||
print_str(s);
|
||||
print_str("\n");
|
||||
print_str(exception_messages[r.int_no]);
|
||||
print_str("\n");
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
typedef struct {
|
||||
u32 ds; // Data segment selector
|
||||
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
|
||||
u32 int_no, err_code; // Interrupt number and error code (if present)
|
||||
u32 eip, cs, eflags, useresp, ss; // Pushed automatically by the CPU
|
||||
} registers_t;
|
||||
|
||||
// CPU exception interrupts
|
||||
// ^ - pushes error code
|
||||
extern void isr00(); // Division by Zero
|
||||
extern void isr01(); // Debug Exception
|
||||
extern void isr02(); // Non Maskable Interrupt
|
||||
extern void isr03(); // Breakpoint
|
||||
extern void isr04(); // Into detected overflow?
|
||||
extern void isr05(); // Out of Bounds
|
||||
extern void isr06(); // Invalid opcode
|
||||
extern void isr07(); // No coprocessor
|
||||
extern void isr08(); //^ Double fault
|
||||
extern void isr09(); // Coprocessor segment overrun
|
||||
extern void isr10(); //^ Bad TSS
|
||||
extern void isr11(); //^ Segment not present
|
||||
extern void isr12(); //^ Stack fault
|
||||
extern void isr13(); //^ General Protection Fault
|
||||
extern void isr14(); //^ Page Fault
|
||||
extern void isr15(); // Unknown Interrupt
|
||||
extern void isr16(); // Coprocessor Fault
|
||||
extern void isr17(); // Alignment check exception
|
||||
extern void isr18(); // Machine check exception
|
||||
extern void isr19(); // Reserved
|
||||
extern void isr20(); // Reserved
|
||||
extern void isr21(); // Reserved
|
||||
extern void isr22(); // Reserved
|
||||
extern void isr23(); // Reserved
|
||||
extern void isr24(); // Reserved
|
||||
extern void isr25(); // Reserved
|
||||
extern void isr26(); // Reserved
|
||||
extern void isr27(); // Reserved
|
||||
extern void isr28(); // Reserved
|
||||
extern void isr29(); // Reserved
|
||||
extern void isr30(); // Reserved
|
||||
extern void isr31(); // Reserved
|
||||
|
||||
void isr_setup();
|
||||
void isr_handler(registers_t r);
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef int i32;
|
||||
typedef unsigned short u16;
|
||||
typedef short i16;
|
||||
typedef unsigned char u8;
|
||||
typedef char i8;
|
||||
|
||||
#define high16(i32) (i32 & 0xffff)
|
||||
#define low16(i32) ((i32>>16) & 0xffff)
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define NULL 0
|
||||
|
||||
#endif
|
|
@ -0,0 +1,110 @@
|
|||
#include "print.h"
|
||||
#include "./platform/drivers/ports.h"
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
char color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4;
|
||||
|
||||
void clear_row(int row) {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
struct Char empty = (struct Char) {
|
||||
character: ' ',
|
||||
color: color,
|
||||
};
|
||||
|
||||
for (int x = 0; x < NUM_COLS; x++) {
|
||||
buffer[x + NUM_COLS * row] = empty;
|
||||
}
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void clear_all() {
|
||||
for (int i = 0; i < NUM_ROWS; i++) {
|
||||
clear_row(i);
|
||||
}
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_newline() {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
col = 0;
|
||||
|
||||
if (row < NUM_ROWS - 1) {
|
||||
row++;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 1; row < NUM_ROWS; row++) {
|
||||
for (int col = 0; col < NUM_COLS; col++) {
|
||||
struct Char character = buffer[col + NUM_COLS * row];
|
||||
buffer[col + NUM_COLS * (row - 1)] = character;
|
||||
}
|
||||
}
|
||||
|
||||
clear_row(NUM_COLS - 1);
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_char(char character) {
|
||||
struct Char* buffer = (struct Char*) 0xb8000;
|
||||
|
||||
if (character == '\n') {
|
||||
print_newline();
|
||||
return;
|
||||
}
|
||||
|
||||
if (col > NUM_COLS) {
|
||||
print_newline();
|
||||
}
|
||||
|
||||
struct Char cr = (struct Char) {
|
||||
character: character,
|
||||
color: color,
|
||||
};
|
||||
buffer[col + NUM_COLS * row] = cr;
|
||||
|
||||
col++;
|
||||
set_cursor_pos(col, row);
|
||||
}
|
||||
|
||||
void print_str(char* str) {
|
||||
for (int i = 0; 1; i++) {
|
||||
char character = (char) str[i];
|
||||
|
||||
if (character == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
print_char(character);
|
||||
}
|
||||
}
|
||||
|
||||
void print_set_color(char foreground, char background) {
|
||||
color = foreground + (background << 4);
|
||||
}
|
||||
|
||||
void set_cursor_pos(int col, int row) {
|
||||
int offset = col + NUM_COLS * row;
|
||||
port_byte_out(REG_SCREEN_CTRL, 14);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
|
||||
port_byte_out(REG_SCREEN_CTRL, 15);
|
||||
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
|
||||
}
|
||||
|
||||
void kernel_msg_ok(char* msg) {
|
||||
char ok_p1[] = "[ ";
|
||||
char ok_p2[] = "OK ";
|
||||
char ok_p3[] = "] ";
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p1);
|
||||
|
||||
print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p2);
|
||||
|
||||
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
|
||||
print_str(ok_p3);
|
||||
print_str(msg);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef PRINT_H
|
||||
#define PRINT_H
|
||||
#define REG_SCREEN_CTRL 0x3d4
|
||||
#define REG_SCREEN_DATA 0x3d5
|
||||
|
||||
enum {
|
||||
PRINT_COLOR_BLACK = 0,
|
||||
PRINT_COLOR_BLUE = 1,
|
||||
PRINT_COLOR_GREEN = 2,
|
||||
PRINT_COLOR_CYAN = 3,
|
||||
PRINT_COLOR_RED = 4,
|
||||
PRINT_COLOR_MAGENTA = 5,
|
||||
PRINT_COLOR_BROWN = 6,
|
||||
PRINT_COLOR_LIGHT_GRAY = 7,
|
||||
PRINT_COLOR_DARK_GRAY = 8,
|
||||
PRINT_COLOR_LIGHT_BLUE = 9,
|
||||
PRINT_COLOR_LIGHT_GREEN = 10,
|
||||
PRINT_COLOR_LIGHT_CYAN = 11,
|
||||
PRINT_COLOR_LIGHT_RED = 12,
|
||||
PRINT_COLOR_PINK = 13,
|
||||
PRINT_COLOR_YELLOW = 14,
|
||||
PRINT_COLOR_WHITE = 15,
|
||||
};
|
||||
|
||||
const static int NUM_COLS = 80;
|
||||
const static int NUM_ROWS = 25;
|
||||
|
||||
struct Char {
|
||||
char character;
|
||||
char color;
|
||||
};
|
||||
|
||||
void clear_row(int row);
|
||||
void clear_all();
|
||||
|
||||
void print_newline();
|
||||
void print_char(char character);
|
||||
void print_set_color(char foreground, char background);
|
||||
void print_str(char* str);
|
||||
|
||||
void set_cursor_pos(int col, int row);
|
||||
|
||||
void kernel_msg_ok(char* msg);
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
#include "strings.h"
|
||||
#include "./platform/types.h"
|
||||
|
||||
void itoa(int n, char str[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do {
|
||||
str[i++] = n % 10 + '0';
|
||||
} while ((n /= 10) > 0);
|
||||
|
||||
if (sign < 0) str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
|
||||
strrev(str);
|
||||
}
|
||||
|
||||
/* K&R */
|
||||
void strrev(char s[]) {
|
||||
int c, i, j;
|
||||
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
|
||||
c = s[i];
|
||||
s[i] = s[j];
|
||||
s[j] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/* K&R */
|
||||
int strlen(char s[]) {
|
||||
int i = 0;
|
||||
while (s[i] != '\0') ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
char* strcpy(char* strDest, const char* strSrc) {
|
||||
if ( (strDest == NULL) || (strSrc == NULL) ) {
|
||||
return NULL;
|
||||
}
|
||||
char* strDestCopy = strDest;
|
||||
while ((*strDest++=*strSrc++)!='\0');
|
||||
return strDestCopy;
|
||||
}
|
||||
|
||||
char* strcnc(char* str1, char* str2) {
|
||||
char* str_dest;
|
||||
strcpy(str_dest, str1);
|
||||
strcpy(str_dest, str2);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
void itoa(int n, char str[]);
|
||||
void strrev(char s[]);
|
||||
int strlen(char s[]);
|
||||
char* strcpy(char* strDest, const char* strSrc);
|
||||
char* strcnc(char* str1, char* str2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#include "util.h"
|
||||
|
||||
void memcpy(char *source, char *dest, int nbytes) {
|
||||
int i;
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
*(dest + i) = *(source + i);
|
||||
}
|
||||
}
|
||||
|
||||
void memset(char *dest, char val, int len) {
|
||||
char *temp = (char *)dest;
|
||||
for(; len !=0; len--) *temp++ = val;
|
||||
}
|
||||
|
||||
void int_to_ascii(int n, char str[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do {
|
||||
str[i++] = n % 10 + '0';
|
||||
} while ((n /= 10) > 0);
|
||||
|
||||
if (sign < 0) str[i++] = '-';
|
||||
str[i] = '\0';
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
void memcpy(char *source, char *dest, int nbytes);
|
||||
void memset(char *dest, char val, int len);
|
||||
void int_to_ascii(int n, char str[]);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue