diff --git a/.gitignore b/.gitignore index 7a6353d..cd33785 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .envrc +.ccls-cache diff --git a/Makefile b/Makefile index e69de29..05874c2 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,82 @@ +TARGET=i686 +ARCHDIR=arch/$(TARGET)/ +SOURCEDIR=src/ +BUILDDIR=build/ + +INCLUDEDIR=$(SOURCEDIR)include/ + +CFLAGS?= +ASFLAGS?= + +# Define flags for C files +CFLAGS:=\ +-O2 \ +-std=gnu99 \ +-ffreestanding \ +-Wall -Wextra \ +-Wno-incompatible-pointer-types\ +-I$(INCLUDEDIR) \ +$(CFLAGS) + +# Define flags for assembly files +ASFLAGS:=\ +-I$(SOURCEIDR)$(INCLUDEDIR) \ +-I$(SOURCEDIR)$(ARCHDIR) \ +$(ASFLAGS) + +LINKERFLAGS:=\ +-ffreestanding \ +-O2 \ +-nostdlib \ +-lgcc + +LIB_OBJS=\ +$(BUILDDIR)$(ARCHDIR)bootstrap.o + +KERNEL_OBJS=\ +$(BUILDDIR)kernel/kernel.o + +OBJS=$(LIB_OBJS) $(KERNEL_OBJS) + +LINKER_PATH=$(SOURCEDIR)$(ARCHDIR)linker.ld + +.PHONY: all clean snowstorm.iso debug +.SUFFIXES: .c .o .s + +$(BUILDDIR)%.o : $(SOURCEDIR)%.c + i686-elf-gcc -c $< -o $@ $(CFLAGS) + +$(BUILDDIR)%.o : $(SOURCEDIR)%.s + i686-elf-as $< -o $@ $(ASFLAGS) + +all: snowstorm.iso + +# Take the kernel file and make a bootable ISO through GRUB +snowstorm.iso: snowstorm.kernel + cp build/snowstorm.kernel build/isodir/boot/snowstorm.kernel + grub-mkrescue -o build/snowstorm.iso build/isodir + +# link all object files together +snowstorm.kernel: $(OBJS) + i686-elf-gcc -T $(LINKER_PATH) -o build/snowstorm.kernel $(OBJS) $(LINKERFLAGS) + grub-file --is-x86-multiboot build/snowstorm.kernel + +debug: CFLAGS += -g -O0 +debug: ASFLAGS += -g +debug: all + + +clean: + rm -f $(OBJS) + rm -f build/snowstorm.kernel + rm -f build/snowstorm.iso + rm -f build/isodir/boot/snowstorm.kernel + +run: all + qemu-system-i386 -d int -no-reboot -kernel build/snowstorm.kernel + +run-debug: debug + qemu-system-i386 -d int -no-reboot -S -gdb tcp::9000 build/snowstorm.iso + +run-debug-kernel: debug + qemu-system-i386 -d int -no-reboot -S -gdb tcp::9000 -kernel build/snowstorm.kernel diff --git a/build/isodir/boot/grub/grub.cfg b/build/isodir/boot/grub/grub.cfg new file mode 100644 index 0000000..f79d6ee --- /dev/null +++ b/build/isodir/boot/grub/grub.cfg @@ -0,0 +1,3 @@ +menuentry "snowstorm" { + multiboot /boot/snowstorm.kernel +} diff --git a/src/arch/i686/bootstrap.s b/src/arch/i686/bootstrap.s index 8b13789..e5eb614 100644 --- a/src/arch/i686/bootstrap.s +++ b/src/arch/i686/bootstrap.s @@ -1 +1,42 @@ +# Declare constants for the multiboot header. +.set ALIGN, 1<<0 # align loaded modules on page boundaries +.set MEMINFO, 1<<1 # provide memory map +.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field +.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header +.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot + +# Declare a multiboot header that marks the program as a kernel. +.section .multiboot.data, "aw" +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +.section .bss, "aw", @nobits +.align 16 +stack_bottom: +.skip (1 << 16) # 64 KiB +stack_top: + +.global boot_page_directory + .align 4096 +boot_page_directory: + .skip 4096 +boot_page_table1: + .skip 4096 + +.section .multiboot.text, "a" +.global _start +.type _start, @function +.extern kernel_main +_start: + mov $stack_top, %esp # The stack grows downwards so it starts at the top + # (We kind of need to have a stack to do anything) + + call kernel_main + + # Infinite loop if kernel_main returns, (which it shouldn't do) + cli +1: hlt + jmp 1b diff --git a/src/arch/i686/linker.ld b/src/arch/i686/linker.ld new file mode 100644 index 0000000..66bf135 --- /dev/null +++ b/src/arch/i686/linker.ld @@ -0,0 +1,29 @@ +ENTRY(_start) + + +SECTIONS +{ + /* Leave 1 Megabyte for GRUB */ + . = 1M; + + .multiboot.data : + { + *(.multiboot.data) /* Take the data from label .multiboot.data from all files and put it in our output file */ + } + + .multiboot.text : + { + *(.multiboot.text) /* Take the data from label .multiboot.data from all files and put it in our output file */ + } + + .bss : + { + *(.bss) /* Take the data from label .multiboot.data from all files and put it in our output file */ + } + + .data : + { + *(.data) /* Take the data from label .multiboot.data from all files and put it in our output file */ + } + +} diff --git a/src/include/strlib.h b/src/include/strlib.h new file mode 100644 index 0000000..82f2628 --- /dev/null +++ b/src/include/strlib.h @@ -0,0 +1,7 @@ +static inline int strlen(char *str) { + int len = 0; + while (str[len] != '\0') { + len += 1; + } + return len; +} diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index e69de29..bcdf1d4 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -0,0 +1,12 @@ +#include +#include +#include "strlib.h" + +uint16_t* VGA_screen = (uint16_t*)0xB8000; +char* text = "Hello World!"; + +void kernel_main() { + for (int i = 0; i < strlen(text); i++) { + VGA_screen[i] = text[i] | 0x0F00; // 0x0F00: two bytes color, two bytes to combine it with text + } +}