Interrupts dont work and I dont know why
This commit is contained in:
commit
dacf0315f3
59 changed files with 1531 additions and 0 deletions
56
Makefile
Normal file
56
Makefile
Normal file
|
@ -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
|
BIN
bin/boot.bin
Normal file
BIN
bin/boot.bin
Normal file
Binary file not shown.
BIN
bin/kernel.bin
Executable file
BIN
bin/kernel.bin
Executable file
Binary file not shown.
4
getinblocks.py
Executable file
4
getinblocks.py
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import sys, math
|
||||||
|
intg = int(sys.argv[1])
|
||||||
|
print(int(math.ceil(intg/512)), end='')
|
BIN
obj/kernel/entry.o
Normal file
BIN
obj/kernel/entry.o
Normal file
Binary file not shown.
BIN
obj/kernel/kernel.o
Normal file
BIN
obj/kernel/kernel.o
Normal file
Binary file not shown.
BIN
obj/kernel/platform/drivers/ports.o
Normal file
BIN
obj/kernel/platform/drivers/ports.o
Normal file
Binary file not shown.
BIN
obj/kernel/platform/interrupts/idt.o
Normal file
BIN
obj/kernel/platform/interrupts/idt.o
Normal file
Binary file not shown.
BIN
obj/kernel/platform/interrupts/int.o
Normal file
BIN
obj/kernel/platform/interrupts/int.o
Normal file
Binary file not shown.
BIN
obj/kernel/platform/interrupts/isr.o
Normal file
BIN
obj/kernel/platform/interrupts/isr.o
Normal file
Binary file not shown.
BIN
obj/kernel/print.o
Normal file
BIN
obj/kernel/print.o
Normal file
Binary file not shown.
BIN
obj/kernel/strings.o
Normal file
BIN
obj/kernel/strings.o
Normal file
Binary file not shown.
BIN
obj/kernel/util.o
Normal file
BIN
obj/kernel/util.o
Normal file
Binary file not shown.
28
old_src/16bit/boot.asm
Normal file
28
old_src/16bit/boot.asm
Normal file
|
@ -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
|
40
old_src/16bit/disk.asm
Normal file
40
old_src/16bit/disk.asm
Normal file
|
@ -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
|
28
old_src/16bit/disk_boot.asm
Normal file
28
old_src/16bit/disk_boot.asm
Normal file
|
@ -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
|
26
old_src/16bit/segmentation.asm
Normal file
26
old_src/16bit/segmentation.asm
Normal file
|
@ -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
|
31
old_src/32bit_gdt.asm
Normal file
31
old_src/32bit_gdt.asm
Normal file
|
@ -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
|
22
old_src/32bit_jump.asm
Normal file
22
old_src/32bit_jump.asm
Normal file
|
@ -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
|
27
old_src/32bit_main.asm
Normal file
27
old_src/32bit_main.asm
Normal file
|
@ -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
|
26
old_src/32bit_print.asm
Normal file
26
old_src/32bit_print.asm
Normal file
|
@ -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
|
3
old_src/function.c
Normal file
3
old_src/function.c
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
int my_function() {
|
||||||
|
return 0xbaba;
|
||||||
|
}
|
7
old_src/functioncalls.c
Normal file
7
old_src/functioncalls.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
void caller() {
|
||||||
|
my_func(0xdede);
|
||||||
|
}
|
||||||
|
|
||||||
|
int my_func(int arg) {
|
||||||
|
return arg;
|
||||||
|
}
|
5
old_src/old-16b/basic_boot.asm
Normal file
5
old_src/old-16b/basic_boot.asm
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
loop:
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
times 510-($-$$) db 0
|
||||||
|
dw 0xaa55
|
18
old_src/old-16b/boot_hello.asm
Normal file
18
old_src/old-16b/boot_hello.asm
Normal file
|
@ -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
|
27
old_src/old-16b/boot_memory.asm
Normal file
27
old_src/old-16b/boot_memory.asm
Normal file
|
@ -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
old_src/old-16b/boot_org.asm
Normal file
0
old_src/old-16b/boot_org.asm
Normal file
38
old_src/old-16b/boot_stack.asm
Normal file
38
old_src/old-16b/boot_stack.asm
Normal file
|
@ -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
|
BIN
old_src/old_bin/boot_hello.bin
Normal file
BIN
old_src/old_bin/boot_hello.bin
Normal file
Binary file not shown.
BIN
old_src/old_bin/boot_memory.bin
Normal file
BIN
old_src/old_bin/boot_memory.bin
Normal file
Binary file not shown.
BIN
old_src/old_bin/boot_simple.bin
Normal file
BIN
old_src/old_bin/boot_simple.bin
Normal file
Binary file not shown.
BIN
old_src/old_bin/boot_stack.bin
Normal file
BIN
old_src/old_bin/boot_stack.bin
Normal file
Binary file not shown.
33
old_src/print.asm
Normal file
33
old_src/print.asm
Normal file
|
@ -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
|
38
old_src/print_hex.asm
Normal file
38
old_src/print_hex.asm
Normal file
|
@ -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
|
BIN
os-image.bin
Normal file
BIN
os-image.bin
Normal file
Binary file not shown.
39
src/boot/boot.asm
Normal file
39
src/boot/boot.asm
Normal file
|
@ -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
|
40
src/boot/disk/disk.asm
Normal file
40
src/boot/disk/disk.asm
Normal file
|
@ -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
|
11
src/boot/kernel.asm
Normal file
11
src/boot/kernel.asm
Normal file
|
@ -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
|
33
src/boot/output/print.asm
Normal file
33
src/boot/output/print.asm
Normal file
|
@ -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
|
38
src/boot/output/print_hex.asm
Normal file
38
src/boot/output/print_hex.asm
Normal file
|
@ -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
|
26
src/boot/output/vga-print.asm
Normal file
26
src/boot/output/vga-print.asm
Normal file
|
@ -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
|
31
src/boot/protected/gdt.asm
Normal file
31
src/boot/protected/gdt.asm
Normal file
|
@ -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
|
24
src/boot/protected/protected-switch.asm
Normal file
24
src/boot/protected/protected-switch.asm
Normal file
|
@ -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
|
4
src/kernel/entry.asm
Normal file
4
src/kernel/entry.asm
Normal file
|
@ -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 $
|
65
src/kernel/kernel.c
Normal file
65
src/kernel/kernel.c
Normal file
|
@ -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");
|
||||||
|
}
|
26
src/kernel/platform/drivers/ports.c
Normal file
26
src/kernel/platform/drivers/ports.c
Normal file
|
@ -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));
|
||||||
|
}
|
4
src/kernel/platform/drivers/ports.h
Normal file
4
src/kernel/platform/drivers/ports.h
Normal file
|
@ -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);
|
20
src/kernel/platform/interrupts/idt.c
Normal file
20
src/kernel/platform/interrupts/idt.c
Normal file
|
@ -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));
|
||||||
|
}
|
27
src/kernel/platform/interrupts/idt.h
Normal file
27
src/kernel/platform/interrupts/idt.h
Normal file
|
@ -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
|
286
src/kernel/platform/interrupts/int.asm
Normal file
286
src/kernel/platform/interrupts/int.asm
Normal file
|
@ -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
|
89
src/kernel/platform/interrupts/isr.c
Normal file
89
src/kernel/platform/interrupts/isr.c
Normal file
|
@ -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");
|
||||||
|
}
|
48
src/kernel/platform/interrupts/isr.h
Normal file
48
src/kernel/platform/interrupts/isr.h
Normal file
|
@ -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);
|
18
src/kernel/platform/types.h
Normal file
18
src/kernel/platform/types.h
Normal file
|
@ -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
|
110
src/kernel/print.c
Normal file
110
src/kernel/print.c
Normal file
|
@ -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);
|
||||||
|
}
|
44
src/kernel/print.h
Normal file
44
src/kernel/print.h
Normal file
|
@ -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
|
48
src/kernel/strings.c
Normal file
48
src/kernel/strings.c
Normal file
|
@ -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);
|
||||||
|
}
|
10
src/kernel/strings.h
Normal file
10
src/kernel/strings.h
Normal file
|
@ -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
|
25
src/kernel/util.c
Normal file
25
src/kernel/util.c
Normal file
|
@ -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';
|
||||||
|
}
|
8
src/kernel/util.h
Normal file
8
src/kernel/util.h
Normal file
|
@ -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…
Add table
Reference in a new issue