commit dacf0315f3a54838d803f9d7af0c24ef04112f1b Author: c0repwn3r Date: Mon May 9 09:45:06 2022 -0400 Interrupts dont work and I dont know why diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c4564c7 --- /dev/null +++ b/Makefile @@ -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 \ No newline at end of file diff --git a/bin/boot.bin b/bin/boot.bin new file mode 100644 index 0000000..1a008f3 Binary files /dev/null and b/bin/boot.bin differ diff --git a/bin/kernel.bin b/bin/kernel.bin new file mode 100755 index 0000000..2877114 Binary files /dev/null and b/bin/kernel.bin differ diff --git a/getinblocks.py b/getinblocks.py new file mode 100755 index 0000000..d269dec --- /dev/null +++ b/getinblocks.py @@ -0,0 +1,4 @@ +#!/usr/bin/python3 +import sys, math +intg = int(sys.argv[1]) +print(int(math.ceil(intg/512)), end='') diff --git a/obj/kernel/entry.o b/obj/kernel/entry.o new file mode 100644 index 0000000..fa6bc54 Binary files /dev/null and b/obj/kernel/entry.o differ diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o new file mode 100644 index 0000000..101664c Binary files /dev/null and b/obj/kernel/kernel.o differ diff --git a/obj/kernel/platform/drivers/ports.o b/obj/kernel/platform/drivers/ports.o new file mode 100644 index 0000000..1b53202 Binary files /dev/null and b/obj/kernel/platform/drivers/ports.o differ diff --git a/obj/kernel/platform/interrupts/idt.o b/obj/kernel/platform/interrupts/idt.o new file mode 100644 index 0000000..3237090 Binary files /dev/null and b/obj/kernel/platform/interrupts/idt.o differ diff --git a/obj/kernel/platform/interrupts/int.o b/obj/kernel/platform/interrupts/int.o new file mode 100644 index 0000000..d09d14e Binary files /dev/null and b/obj/kernel/platform/interrupts/int.o differ diff --git a/obj/kernel/platform/interrupts/isr.o b/obj/kernel/platform/interrupts/isr.o new file mode 100644 index 0000000..925c526 Binary files /dev/null and b/obj/kernel/platform/interrupts/isr.o differ diff --git a/obj/kernel/print.o b/obj/kernel/print.o new file mode 100644 index 0000000..6a393f3 Binary files /dev/null and b/obj/kernel/print.o differ diff --git a/obj/kernel/strings.o b/obj/kernel/strings.o new file mode 100644 index 0000000..107b607 Binary files /dev/null and b/obj/kernel/strings.o differ diff --git a/obj/kernel/util.o b/obj/kernel/util.o new file mode 100644 index 0000000..5e77ddb Binary files /dev/null and b/obj/kernel/util.o differ diff --git a/old_src/16bit/boot.asm b/old_src/16bit/boot.asm new file mode 100644 index 0000000..259357d --- /dev/null +++ b/old_src/16bit/boot.asm @@ -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 \ No newline at end of file diff --git a/old_src/16bit/disk.asm b/old_src/16bit/disk.asm new file mode 100644 index 0000000..4102835 --- /dev/null +++ b/old_src/16bit/disk.asm @@ -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 \ No newline at end of file diff --git a/old_src/16bit/disk_boot.asm b/old_src/16bit/disk_boot.asm new file mode 100644 index 0000000..bd8fdbd --- /dev/null +++ b/old_src/16bit/disk_boot.asm @@ -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 \ No newline at end of file diff --git a/old_src/16bit/segmentation.asm b/old_src/16bit/segmentation.asm new file mode 100644 index 0000000..724b215 --- /dev/null +++ b/old_src/16bit/segmentation.asm @@ -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 \ No newline at end of file diff --git a/old_src/32bit_gdt.asm b/old_src/32bit_gdt.asm new file mode 100644 index 0000000..2618221 --- /dev/null +++ b/old_src/32bit_gdt.asm @@ -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 \ No newline at end of file diff --git a/old_src/32bit_jump.asm b/old_src/32bit_jump.asm new file mode 100644 index 0000000..b49e7c0 --- /dev/null +++ b/old_src/32bit_jump.asm @@ -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 \ No newline at end of file diff --git a/old_src/32bit_main.asm b/old_src/32bit_main.asm new file mode 100644 index 0000000..23a65fa --- /dev/null +++ b/old_src/32bit_main.asm @@ -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 \ No newline at end of file diff --git a/old_src/32bit_print.asm b/old_src/32bit_print.asm new file mode 100644 index 0000000..a9055e3 --- /dev/null +++ b/old_src/32bit_print.asm @@ -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 \ No newline at end of file diff --git a/old_src/function.c b/old_src/function.c new file mode 100644 index 0000000..41a7ba3 --- /dev/null +++ b/old_src/function.c @@ -0,0 +1,3 @@ +int my_function() { + return 0xbaba; +} \ No newline at end of file diff --git a/old_src/functioncalls.c b/old_src/functioncalls.c new file mode 100644 index 0000000..17435f7 --- /dev/null +++ b/old_src/functioncalls.c @@ -0,0 +1,7 @@ +void caller() { + my_func(0xdede); +} + +int my_func(int arg) { + return arg; +} \ No newline at end of file diff --git a/old_src/old-16b/basic_boot.asm b/old_src/old-16b/basic_boot.asm new file mode 100644 index 0000000..671090b --- /dev/null +++ b/old_src/old-16b/basic_boot.asm @@ -0,0 +1,5 @@ +loop: + jmp loop + +times 510-($-$$) db 0 +dw 0xaa55 diff --git a/old_src/old-16b/boot_hello.asm b/old_src/old-16b/boot_hello.asm new file mode 100644 index 0000000..29d250e --- /dev/null +++ b/old_src/old-16b/boot_hello.asm @@ -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 diff --git a/old_src/old-16b/boot_memory.asm b/old_src/old-16b/boot_memory.asm new file mode 100644 index 0000000..1bd3e7a --- /dev/null +++ b/old_src/old-16b/boot_memory.asm @@ -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 \ No newline at end of file diff --git a/old_src/old-16b/boot_org.asm b/old_src/old-16b/boot_org.asm new file mode 100644 index 0000000..e69de29 diff --git a/old_src/old-16b/boot_stack.asm b/old_src/old-16b/boot_stack.asm new file mode 100644 index 0000000..8fd1dd4 --- /dev/null +++ b/old_src/old-16b/boot_stack.asm @@ -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 \ No newline at end of file diff --git a/old_src/old_bin/boot_hello.bin b/old_src/old_bin/boot_hello.bin new file mode 100644 index 0000000..6440294 Binary files /dev/null and b/old_src/old_bin/boot_hello.bin differ diff --git a/old_src/old_bin/boot_memory.bin b/old_src/old_bin/boot_memory.bin new file mode 100644 index 0000000..6c2eb32 Binary files /dev/null and b/old_src/old_bin/boot_memory.bin differ diff --git a/old_src/old_bin/boot_simple.bin b/old_src/old_bin/boot_simple.bin new file mode 100644 index 0000000..980ee55 Binary files /dev/null and b/old_src/old_bin/boot_simple.bin differ diff --git a/old_src/old_bin/boot_stack.bin b/old_src/old_bin/boot_stack.bin new file mode 100644 index 0000000..0385d5b Binary files /dev/null and b/old_src/old_bin/boot_stack.bin differ diff --git a/old_src/print.asm b/old_src/print.asm new file mode 100644 index 0000000..5fd8309 --- /dev/null +++ b/old_src/print.asm @@ -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 \ No newline at end of file diff --git a/old_src/print_hex.asm b/old_src/print_hex.asm new file mode 100644 index 0000000..e6df82b --- /dev/null +++ b/old_src/print_hex.asm @@ -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 \ No newline at end of file diff --git a/os-image.bin b/os-image.bin new file mode 100644 index 0000000..de78a72 Binary files /dev/null and b/os-image.bin differ diff --git a/src/boot/boot.asm b/src/boot/boot.asm new file mode 100644 index 0000000..4a4d793 --- /dev/null +++ b/src/boot/boot.asm @@ -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 \ No newline at end of file diff --git a/src/boot/disk/disk.asm b/src/boot/disk/disk.asm new file mode 100644 index 0000000..4102835 --- /dev/null +++ b/src/boot/disk/disk.asm @@ -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 \ No newline at end of file diff --git a/src/boot/kernel.asm b/src/boot/kernel.asm new file mode 100644 index 0000000..47749af --- /dev/null +++ b/src/boot/kernel.asm @@ -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 \ No newline at end of file diff --git a/src/boot/output/print.asm b/src/boot/output/print.asm new file mode 100644 index 0000000..5fd8309 --- /dev/null +++ b/src/boot/output/print.asm @@ -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 \ No newline at end of file diff --git a/src/boot/output/print_hex.asm b/src/boot/output/print_hex.asm new file mode 100644 index 0000000..e6df82b --- /dev/null +++ b/src/boot/output/print_hex.asm @@ -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 \ No newline at end of file diff --git a/src/boot/output/vga-print.asm b/src/boot/output/vga-print.asm new file mode 100644 index 0000000..a9055e3 --- /dev/null +++ b/src/boot/output/vga-print.asm @@ -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 \ No newline at end of file diff --git a/src/boot/protected/gdt.asm b/src/boot/protected/gdt.asm new file mode 100644 index 0000000..2618221 --- /dev/null +++ b/src/boot/protected/gdt.asm @@ -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 \ No newline at end of file diff --git a/src/boot/protected/protected-switch.asm b/src/boot/protected/protected-switch.asm new file mode 100644 index 0000000..53708d7 --- /dev/null +++ b/src/boot/protected/protected-switch.asm @@ -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 \ No newline at end of file diff --git a/src/kernel/entry.asm b/src/kernel/entry.asm new file mode 100644 index 0000000..a8d38ec --- /dev/null +++ b/src/kernel/entry.asm @@ -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 $ \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c new file mode 100644 index 0000000..a176882 --- /dev/null +++ b/src/kernel/kernel.c @@ -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"); +} \ No newline at end of file diff --git a/src/kernel/platform/drivers/ports.c b/src/kernel/platform/drivers/ports.c new file mode 100644 index 0000000..34a48db --- /dev/null +++ b/src/kernel/platform/drivers/ports.c @@ -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)); +} \ No newline at end of file diff --git a/src/kernel/platform/drivers/ports.h b/src/kernel/platform/drivers/ports.h new file mode 100644 index 0000000..d616f0e --- /dev/null +++ b/src/kernel/platform/drivers/ports.h @@ -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); \ No newline at end of file diff --git a/src/kernel/platform/interrupts/idt.c b/src/kernel/platform/interrupts/idt.c new file mode 100644 index 0000000..7c3f48d --- /dev/null +++ b/src/kernel/platform/interrupts/idt.c @@ -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)); +} \ No newline at end of file diff --git a/src/kernel/platform/interrupts/idt.h b/src/kernel/platform/interrupts/idt.h new file mode 100644 index 0000000..93c723e --- /dev/null +++ b/src/kernel/platform/interrupts/idt.h @@ -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 \ No newline at end of file diff --git a/src/kernel/platform/interrupts/int.asm b/src/kernel/platform/interrupts/int.asm new file mode 100644 index 0000000..9edc58e --- /dev/null +++ b/src/kernel/platform/interrupts/int.asm @@ -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 diff --git a/src/kernel/platform/interrupts/isr.c b/src/kernel/platform/interrupts/isr.c new file mode 100644 index 0000000..89ec4ea --- /dev/null +++ b/src/kernel/platform/interrupts/isr.c @@ -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"); +} \ No newline at end of file diff --git a/src/kernel/platform/interrupts/isr.h b/src/kernel/platform/interrupts/isr.h new file mode 100644 index 0000000..3d00a26 --- /dev/null +++ b/src/kernel/platform/interrupts/isr.h @@ -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); \ No newline at end of file diff --git a/src/kernel/platform/types.h b/src/kernel/platform/types.h new file mode 100644 index 0000000..e18f414 --- /dev/null +++ b/src/kernel/platform/types.h @@ -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 \ No newline at end of file diff --git a/src/kernel/print.c b/src/kernel/print.c new file mode 100644 index 0000000..014de03 --- /dev/null +++ b/src/kernel/print.c @@ -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); +} \ No newline at end of file diff --git a/src/kernel/print.h b/src/kernel/print.h new file mode 100644 index 0000000..edd8a9e --- /dev/null +++ b/src/kernel/print.h @@ -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 \ No newline at end of file diff --git a/src/kernel/strings.c b/src/kernel/strings.c new file mode 100644 index 0000000..79897f8 --- /dev/null +++ b/src/kernel/strings.c @@ -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); +} \ No newline at end of file diff --git a/src/kernel/strings.h b/src/kernel/strings.h new file mode 100644 index 0000000..ee4402a --- /dev/null +++ b/src/kernel/strings.h @@ -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 \ No newline at end of file diff --git a/src/kernel/util.c b/src/kernel/util.c new file mode 100644 index 0000000..e945d94 --- /dev/null +++ b/src/kernel/util.c @@ -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'; +} \ No newline at end of file diff --git a/src/kernel/util.h b/src/kernel/util.h new file mode 100644 index 0000000..889ccb0 --- /dev/null +++ b/src/kernel/util.h @@ -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 \ No newline at end of file