diff --git a/.gitignore b/.gitignore index 7f519d8..f3b1f83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -disk.hdd /limine +/iso_root +*.iso diff --git a/Makefile b/Makefile index 835ce42..8c3acf4 100644 --- a/Makefile +++ b/Makefile @@ -1,30 +1,41 @@ -.PHONY: all disk clean +.PHONY: all clean prepare cleanall iso -disk: +all: + make -C kernel all + +prepare: if [ ! -d limine ]; then \ - git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1; \ - make -C limine; \ + mkdir limine; \ + cd limine; \ + git init; \ + git remote add origin https://github.com/limine-bootloader/limine.git; \ + git fetch origin 9246bb78f446962aae5b0a291db4be32f9866ba6; \ + git reset --hard FETCH_HEAD; \ + make; \ fi - make -C kernel - rm -f disk.hdd - dd if=/dev/zero bs=1M count=0 seek=64 of=disk.hdd - PATH=$$PATH:/usr/sbin:/sbin sgdisk disk.hdd -n 1:2048 -t 1:ef00 -m 1 - ./limine/limine bios-install disk.hdd - mformat -i disk.hdd@@1M - mmd -i disk.hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine - mcopy -i disk.hdd@@1M kernel/mop2 ::/boot - mcopy -i disk.hdd@@1M limine.conf limine/limine-bios.sys ::/boot/limine - mcopy -i disk.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT + +cleanall: + make clean + rm -rf limine clean: - rm -rf limine disk.hdd make -C kernel clean + rm -f mop2.iso -all: disk - -run: - qemu-system-x86_64 \ - -d guest_errors \ - -serial stdio \ - -hda disk.hdd +iso: + rm -rf iso_root + mkdir -p iso_root/boot + cp -v kernel/mop2 iso_root/boot + mkdir -p iso_root/boot/limine + cp -v limine.conf limine/limine-bios.sys limine/limine-bios-cd.bin \ + limine/limine-uefi-cd.bin iso_root/boot/limine + mkdir -p iso_root/EFI/BOOT + cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT + cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT + xorriso -as mkisofs -R -r -J -b boot/limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \ + -apm-block-size 2048 --efi-boot boot/limine/limine-uefi-cd.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + iso_root -o mop2.iso + ./limine/limine bios-install mop2.iso diff --git a/kernel/.gitignore b/kernel/.gitignore index a6eee84..9a8d9f9 100644 --- a/kernel/.gitignore +++ b/kernel/.gitignore @@ -1,2 +1,3 @@ *.o mop2 +*.iso diff --git a/kernel/Makefile b/kernel/Makefile index 3667676..8e03705 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,53 +1,36 @@ .PHONY: all clean -CC := x86_64-elf-gcc -LD := x86_64-elf-ld +ARCH ?= x86_64 -override CFLAGS = -Wall \ - -Wextra \ - -ffreestanding \ - -fno-stack-protector \ - -fno-stack-check \ - -fno-lto \ - -fno-PIC \ - -ffunction-sections \ - -fdata-sections \ - -m64 \ - -march=x86-64 \ - -mabi=sysv \ - -mno-80387 \ - -mno-mmx \ - -mno-sse \ - -mno-sse2 \ - -mno-red-zone \ - -mcmodel=kernel \ - -I. \ +CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon + +CFLAGS += -I. \ -I../limine \ -DPRINTF_INCLUDE_CONFIG_H=1 -override LDFLAGS = \ - -m elf_x86_64 \ - -nostdlib \ - -static \ - -z max-page-size=0x1000 \ - --gc-sections \ - -T link.ld +LDFLAGS := -nostdlib -static -T arch/$(ARCH)/link.ld -override NASMFLAGS = \ - -felf64 \ - -Wall \ - -F dwarf -g +include arch/$(ARCH)/$(ARCH).mk +include extconf/extra.mk -override SRCFILES := $(shell find -L . -type f 2>/dev/null | LC_ALL=C sort) -override CFILES := $(filter %.c,$(SRCFILES)) -override ASFILES := $(filter %.asm,$(SRCFILES)) -override OBJ := $(patsubst %.c,%.o,$(CFILES)) $(patsubst %.asm,%.o,$(ASFILES)) +SRCFILES := $(wildcard *.c) \ + $(wildcard printf/*.c) \ + $(wildcard bitmap/*.c) \ + $(wildcard pmm/*.c) \ + $(wildcard bootinfo/*.c) \ + $(wildcard hal/*.c) \ + $(wildcard hal/$(ARCH)/*.c) \ + $(wildcard hal/$(ARCH)/*.S) \ + $(wildcard *.S) +CFILES := $(filter %.c,$(SRCFILES)) +ASFILES := $(filter %.S,$(SRCFILES)) +OBJ := $(patsubst %.c,%.o,$(CFILES)) $(patsubst %.S,%.o,$(ASFILES)) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ -%.o: %.asm - nasm $(NASMFLAGS) $< -o $@ +%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ all: mop2 diff --git a/kernel/ansi_colors.h b/kernel/ansi_colors.h new file mode 100644 index 0000000..203f9a8 --- /dev/null +++ b/kernel/ansi_colors.h @@ -0,0 +1,85 @@ +#ifndef ANSI_COLORS_H_ +#define ANSI_COLORS_H_ + +/* + * This is free and unencumbered software released into the public domain. + * + * For more information, please refer to + */ + +//Regular text +#define BLK "\e[0;30m" +#define RED "\e[0;31m" +#define GRN "\e[0;32m" +#define YEL "\e[0;33m" +#define BLU "\e[0;34m" +#define MAG "\e[0;35m" +#define CYN "\e[0;36m" +#define WHT "\e[0;37m" + +//Regular bold text +#define BBLK "\e[1;30m" +#define BRED "\e[1;31m" +#define BGRN "\e[1;32m" +#define BYEL "\e[1;33m" +#define BBLU "\e[1;34m" +#define BMAG "\e[1;35m" +#define BCYN "\e[1;36m" +#define BWHT "\e[1;37m" + +//Regular underline text +#define UBLK "\e[4;30m" +#define URED "\e[4;31m" +#define UGRN "\e[4;32m" +#define UYEL "\e[4;33m" +#define UBLU "\e[4;34m" +#define UMAG "\e[4;35m" +#define UCYN "\e[4;36m" +#define UWHT "\e[4;37m" + +//Regular background +#define BLKB "\e[40m" +#define REDB "\e[41m" +#define GRNB "\e[42m" +#define YELB "\e[43m" +#define BLUB "\e[44m" +#define MAGB "\e[45m" +#define CYNB "\e[46m" +#define WHTB "\e[47m" + +//High intensty background +#define BLKHB "\e[0;100m" +#define REDHB "\e[0;101m" +#define GRNHB "\e[0;102m" +#define YELHB "\e[0;103m" +#define BLUHB "\e[0;104m" +#define MAGHB "\e[0;105m" +#define CYNHB "\e[0;106m" +#define WHTHB "\e[0;107m" + +//High intensty text +#define HBLK "\e[0;90m" +#define HRED "\e[0;91m" +#define HGRN "\e[0;92m" +#define HYEL "\e[0;93m" +#define HBLU "\e[0;94m" +#define HMAG "\e[0;95m" +#define HCYN "\e[0;96m" +#define HWHT "\e[0;97m" + +//Bold high intensity text +#define BHBLK "\e[1;90m" +#define BHRED "\e[1;91m" +#define BHGRN "\e[1;92m" +#define BHYEL "\e[1;93m" +#define BHBLU "\e[1;94m" +#define BHMAG "\e[1;95m" +#define BHCYN "\e[1;96m" +#define BHWHT "\e[1;97m" + +//Reset +#define reset "\e[0m" +#define CRESET "\e[0m" +#define COLOR_RESET "\e[0m" + +#endif // ANSI_COLORS_H_ diff --git a/kernel/link.ld b/kernel/arch/x86_64/link.ld similarity index 51% rename from kernel/link.ld rename to kernel/arch/x86_64/link.ld index b8e1485..77e6294 100644 --- a/kernel/link.ld +++ b/kernel/arch/x86_64/link.ld @@ -1,56 +1,57 @@ /* Tell the linker that we want an x86_64 ELF64 output file */ OUTPUT_FORMAT(elf64-x86-64) +OUTPUT_ARCH(i386:x86-64) -/* We want the symbol kmain to be our entry point */ +/* We want the symbol _start to be our entry point */ ENTRY(kmain) /* Define the program headers we want so the bootloader gives us the right */ -/* MMU permissions; this also allows us to exert more control over the linking */ -/* process. */ +/* MMU permissions */ PHDRS { - limine_requests PT_LOAD; - text PT_LOAD; - rodata PT_LOAD; - data PT_LOAD; + text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ + rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ + data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ + dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Dynamic PHDR for relocations */ } SECTIONS { - /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* We wanna be placed in the topmost 2GiB of the address space, for optimisations */ /* and because that is what the Limine spec mandates. */ /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ /* that is the beginning of the region. */ . = 0xffffffff80000000; - /* Define a section to contain the Limine requests and assign it to its own PHDR */ - .limine_requests : { - KEEP(*(.limine_requests_start)) - KEEP(*(.limine_requests)) - KEEP(*(.limine_requests_end)) - } :limine_requests - - /* Move to the next memory page for .text */ - . = ALIGN(CONSTANT(MAXPAGESIZE)); - + kernel_start = .; + kernel_text_start = .; .text : { *(.text .text.*) } :text + kernel_text_end = .; /* Move to the next memory page for .rodata */ - . = ALIGN(CONSTANT(MAXPAGESIZE)); + . += CONSTANT(MAXPAGESIZE); + kernel_rodata_start = .; .rodata : { *(.rodata .rodata.*) } :rodata + kernel_rodata_end = .; /* Move to the next memory page for .data */ - . = ALIGN(CONSTANT(MAXPAGESIZE)); + . += CONSTANT(MAXPAGESIZE); + kernel_data_start = .; .data : { *(.data .data.*) } :data + /* Dynamic section for relocations, both in its own PHDR and inside data PHDR */ + .dynamic : { + *(.dynamic) + } :data :dynamic + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ /* unnecessary zeros will be written to the binary. */ /* If you need, for example, .init_array and .fini_array, those should be placed */ @@ -59,10 +60,13 @@ SECTIONS *(.bss .bss.*) *(COMMON) } :data + kernel_data_end = .; - /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /* Discard .note.* and .eh_frame since they may cause issues on some hosts. */ /DISCARD/ : { - *(.eh_frame*) + *(.eh_frame) *(.note .note.*) } + + kernel_end = .; } diff --git a/kernel/arch/x86_64/x86_64.mk b/kernel/arch/x86_64/x86_64.mk new file mode 100644 index 0000000..a739029 --- /dev/null +++ b/kernel/arch/x86_64/x86_64.mk @@ -0,0 +1,22 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld + +CFLAGS += -m64 \ + -fPIE \ + -mno-80387 \ + -mno-mmx \ + -mno-sse \ + -nostartfiles \ + -nostdlib \ + -mno-sse2 \ + -mno-red-zone \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-lto + +LDFLAGS += -m elf_x86_64 \ + -pie \ + --no-dynamic-linker \ + -z text \ + -z max-page-size=0x1000 + diff --git a/kernel/banner.h b/kernel/banner.h new file mode 100644 index 0000000..dd3e03c --- /dev/null +++ b/kernel/banner.h @@ -0,0 +1,14 @@ +#ifndef BANNER_H_ +#define BANNER_H_ + +#define BANNER_TEXT \ +"___ ___ _____ _____ ______ _ _ \n" \ +"| \\/ | | _ / ___| | ___ \\ (_) | | \n" \ +"| . . |_ _ | | | \\ `--. | |_/ / __ ___ _ ___ ___| |_ \n" \ +"| |\\/| | | | | | | | |`--. \\ | __/ '__/ _ \\| |/ _ \\/ __| __|\n" \ +"| | | | |_| | \\ \\_/ /\\__/ / | | | | | (_) | | __/ (__| |_ \n" \ +"\\_| |_/\\__, | \\___/\\____/ \\_| |_| \\___/| |\\___|\\___|\\__|\n" \ +" __/ | _/ | \n" \ +" |___/ |__/ \n" \ + +#endif // BANNER_H_ diff --git a/kernel/bitmap/bitmap.c b/kernel/bitmap/bitmap.c new file mode 100644 index 0000000..f38c398 --- /dev/null +++ b/kernel/bitmap/bitmap.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include "bitmap.h" + +#define DIV_ROUNDUP(num, div) ((num + div - 1) / div) + +void *bitmap_toptr(BitMap *bm, size_t block) { + uint8_t *ptr = (uint8_t *)(bm->mem_start + (block * BITMAP_BLOCK_SIZE)); + return (void *)ptr; +} + +size_t bitmap_toblock(BitMap *bm, void *ptr) { + uint8_t *p = ptr; + return (size_t)(p - bm->mem_start) / BITMAP_BLOCK_SIZE; +} + +size_t bitmap_toblock_roundup(BitMap *bm, void *ptr) { + uint8_t *p = ptr; + return (size_t)DIV_ROUNDUP((size_t)(p - bm->mem_start), BITMAP_BLOCK_SIZE); +} + +size_t bitmap_calcsize(size_t total) { + size_t nblocks = DIV_ROUNDUP(total, BITMAP_BLOCK_SIZE); + size_t nbytes = DIV_ROUNDUP(nblocks, 8); + return nbytes; +} + +bool bitmap_get(BitMap *bm, size_t block) { + size_t elem = block / BITMAP_BLOCKS_PER_BYTE; + size_t off = block % BITMAP_BLOCKS_PER_BYTE; + return (bm->map[elem] & (1 << off)) != 0; +} + +void bitmap_set(BitMap *bm, size_t block, bool value) { + size_t elem = block / BITMAP_BLOCKS_PER_BYTE; + size_t off = block % BITMAP_BLOCKS_PER_BYTE; + if (value) { + bm->map[elem] |= (1 << off); + } else { + bm->map[elem] &= ~(1 << off); + } +} + +void bitmap_markblocks(BitMap *bm, size_t start, size_t size, bool value) { + if (!value && start < bm->last_deep_frag) { + bm->last_deep_frag = start; + } + + for (size_t i = start; i < start + size; i++) { + bitmap_set(bm, i, value); + } + + bm->alloc_blocks += value ? size : -size; +} + +void bitmap_markregion(BitMap *bm, void *baseptr, size_t size, bool is_used) { + size_t base, size1; + + if (is_used) { + base = bitmap_toblock(bm, baseptr); + size1 = DIV_ROUNDUP(size, BITMAP_BLOCK_SIZE); + } else { + base = bitmap_toblock(bm, baseptr); + size1 = size / BITMAP_BLOCK_SIZE; + } + bitmap_markblocks(bm, base, size1, is_used); +} + +size_t bitmap_freeregion(BitMap *bm, size_t blocks) { + size_t curregstart = bm->last_deep_frag; + size_t curregsize = 0; + for (size_t i = curregstart; i < bm->nblocks; i++) { + if (bitmap_get(bm, i)) { + curregsize = 0; + curregstart = i + 1; + } else { + if (blocks == 1) { + bm->last_deep_frag = curregstart + 1; + } + + curregsize++; + if (curregsize >= blocks) { + return curregstart; + } + } + } + return BITMAP_INVALID_BLOCK; +} + +void *bitmap_alloc(BitMap *bm, size_t blocks) { + if (!blocks) { + return NULL; + } + + size_t pickedreg = bitmap_freeregion(bm, blocks); + if (pickedreg == BITMAP_INVALID_BLOCK) { + return NULL; + } + + bitmap_markblocks(bm, pickedreg, blocks, 1); + return bitmap_toptr(bm, pickedreg); +} + +void bitmap_free(BitMap *bm, void *base, size_t blocks) { + bitmap_markregion(bm, base, BITMAP_BLOCK_SIZE * blocks, 0); +} + +size_t bitmap_allocpageframe(BitMap *bm) { + size_t pickedreg = bitmap_freeregion(bm, 1); + bitmap_markblocks(bm, pickedreg, 1, 1); + return (bm->mem_start + (pickedreg * BITMAP_BLOCK_SIZE)); +} + +void bitmap_freepageframe(BitMap *bm, void *addr) { + bitmap_markregion(bm, addr, BITMAP_BLOCK_SIZE * 1, 0); +} diff --git a/kernel/bitmap/bitmap.h b/kernel/bitmap/bitmap.h new file mode 100644 index 0000000..0cd188e --- /dev/null +++ b/kernel/bitmap/bitmap.h @@ -0,0 +1,36 @@ +#ifndef BITMAP_BITMAP_H_ +#define BITMAP_BITMAP_H_ + +#include +#include +#include + +typedef struct { + uint8_t *map; + size_t nblocks; + size_t nbytes; + size_t alloc_blocks; + size_t last_deep_frag; + uintptr_t mem_start; + bool init; +} BitMap; + +#define BITMAP_BLOCKS_PER_BYTE 8 +#define BITMAP_BLOCK_SIZE 0x1000 +#define BITMAP_INVALID_BLOCK ((size_t)-1) + +void *bitmap_toptr(BitMap *bm, size_t block); +size_t bitmap_toblock(BitMap *bm, void *ptr); +size_t bitmap_toblock_roundup(BitMap *bm, void *ptr); +size_t bitmap_calcsize(size_t total); +bool bitmap_get(BitMap *bm, size_t block); +void bitmap_set(BitMap *bm, size_t block, bool value); +void bitmap_markblocks(BitMap *bm, size_t start, size_t size, bool value); +void bitmap_markregion(BitMap *bm, void *baseptr, size_t size, bool is_used); +size_t bitmap_freeregion(BitMap *bm, size_t blocks); +void *bitmap_alloc(BitMap *bm, size_t blocks); +void bitmap_free(BitMap *bm, void *base, size_t blocks); +size_t bitmap_allocpageframe(BitMap *bm); +void bitmap_freepageframe(BitMap *bm, void *addr); + +#endif // BITMAP_BITMAP_H_ diff --git a/kernel/bootinfo/bootinfo.c b/kernel/bootinfo/bootinfo.c new file mode 100644 index 0000000..9e2068c --- /dev/null +++ b/kernel/bootinfo/bootinfo.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include "bootinfo.h" +#include "hal/hal.h" + +BootInfo BOOT_INFO; + +static volatile struct limine_paging_mode_request PAGING_REQ = { + .id = LIMINE_PAGING_MODE_REQUEST, + .revision = 0, +#if defined(__x86_64__) + .mode = LIMINE_PAGING_MODE_X86_64_4LVL, +#else +# error "Paging mode is unknown for this architecture" +#endif +}; + +static volatile struct limine_kernel_address_request KERN_ADDR_REQ = { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0, +}; + +static volatile struct limine_hhdm_request HHDM_REQ = { + .id = LIMINE_HHDM_REQUEST, .revision = 0, +}; + +static volatile struct limine_memmap_request MEMMAP_REQ = { + .id = LIMINE_MEMMAP_REQUEST, .revision = 0, +}; + +static volatile struct limine_smp_request SMP_REQ = { + .id = LIMINE_SMP_REQUEST, .revision = 0, +}; + +static volatile struct limine_rsdp_request RSDP_REQ = { + .id = LIMINE_RSDP_REQUEST, .revision = 0, +}; + +void bootinfo_init(void) { + struct limine_paging_mode_response *pagingres = PAGING_REQ.response; +#if defined(__x86_64__) + if (pagingres->mode != LIMINE_PAGING_MODE_X86_64_4LVL) { +#endif + hal_hang(); + } + + struct limine_hhdm_response *hhdmres = HHDM_REQ.response; + BOOT_INFO.hhdm_off = hhdmres->offset; + + struct limine_kernel_address_response *kernaddrres = KERN_ADDR_REQ.response; + BOOT_INFO.kern_virtbase = kernaddrres->virtual_base; + BOOT_INFO.kern_physbase = kernaddrres->physical_base; + + struct limine_memmap_response *memmapres = MEMMAP_REQ.response; + BOOT_INFO.memmap_entries = memmapres->entries; + BOOT_INFO.memmap_entrycount = memmapres->entry_count; + + BOOT_INFO.memmap_total = 0; + for (size_t i = 0; i < memmapres->entry_count; i++) { + struct limine_memmap_entry *entry = memmapres->entries[i]; + if (entry->type != LIMINE_MEMMAP_RESERVED) { + BOOT_INFO.memmap_total += entry->length; + } + } + + struct limine_smp_response *smpres = SMP_REQ.response; + BOOT_INFO.smp = smpres; + + BOOT_INFO.smp_bspindex = (uint64_t)(-1); + for (size_t i = 0; i < smpres->cpu_count; i++) { + struct limine_smp_info *entry = smpres->cpus[i]; + if (entry->lapic_id == smpres->bsp_lapic_id) { + BOOT_INFO.smp_bspindex = i; + } + } + if (BOOT_INFO.smp_bspindex == (uint64_t)-1) { + hal_hang(); + } + + struct limine_rsdp_response *rsdpres = RSDP_REQ.response; + BOOT_INFO.rsdp = (size_t)rsdpres->address - BOOT_INFO.hhdm_off; +} diff --git a/kernel/bootinfo/bootinfo.h b/kernel/bootinfo/bootinfo.h new file mode 100644 index 0000000..10d9f7b --- /dev/null +++ b/kernel/bootinfo/bootinfo.h @@ -0,0 +1,33 @@ +#ifndef BOOTINFO_BOOTINFO_H_ +#define BOOTINFO_BOOTINFO_H_ + +#include +#include +#include + +extern uint64_t kernel_text_start, kernel_text_end, + kernel_rodata_start, kernel_rodata_end, + kernel_data_start, kernel_data_end, + kernel_start, kernel_end; + +typedef struct { + // Higher Half Direct Map: https://github.com/dreamportdev/Osdev-Notes/blob/master/01_Build_Process/02_Boot_Protocols.md#limine-protocol + size_t hhdm_off; + size_t kern_virtbase; + size_t kern_physbase; + size_t rsdp; + size_t memmap_total; + uint64_t memmap_entrycount; + LIMINE_PTR(struct limine_memmap_entry **) memmap_entries; + LIMINE_PTR(struct limine_smp_response *) smp; + uint64_t smp_bspindex; +} BootInfo; + +extern BootInfo BOOT_INFO; + +#define IS_IN_HHDM(a) ((size_t)a >= BOOT_INFO.hhdm_off \ + && (size_t)a <= BOOT_INFO.hhdm_off + BOOT_INFO.memmap_total) + +void bootinfo_init(void); + +#endif // BOOTINFO_BOOTINFO_H_ diff --git a/kernel/com1.c b/kernel/com1.c deleted file mode 100644 index 8db08eb..0000000 --- a/kernel/com1.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#define COM1 0x3f8 - -void com1_init(void) { - serial_outb(COM1 + 1, 0x00); // no intr - serial_outb(COM1 + 3, 0x80); // enable DLAB - serial_outb(COM1 + 0, 0x01); // 115200 baudrate - serial_outb(COM1 + 1, 0x00); - serial_outb(COM1 + 3, 0x03); // 8N1 - serial_outb(COM1 + 2, 0xc7); // fifo - serial_outb(COM1 + 4, 0x0b); // irqs enabled, rts/dsr set -} - -int32 com1_is_ready(void) { - return serial_inb(COM1 + 5) & 0x20; -} - -void com1_putch(char c) { - while (!com1_is_ready()); - serial_outb(COM1, c); -} - -void com1_puts(char *s) { - while (*s) com1_putch(*s++); -} - -void putchar_(char c) { - com1_putch(c); -} - diff --git a/kernel/com1.h b/kernel/com1.h deleted file mode 100644 index 1482fb6..0000000 --- a/kernel/com1.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef COM1_H_ -#define COM1_H_ - -void com1_init(void); - -#endif // COM1_H_ diff --git a/kernel/compiler/attr.h b/kernel/compiler/attr.h new file mode 100644 index 0000000..e4e262f --- /dev/null +++ b/kernel/compiler/attr.h @@ -0,0 +1,6 @@ +#ifndef COMPILER_ATTR_H_ +#define COMPILER_ATTR_H_ + +#define PACKED __attribute__((packed)) + +#endif // COMPILER_ATTR_H_ diff --git a/kernel/errors.h b/kernel/errors.h deleted file mode 100644 index ac44779..0000000 --- a/kernel/errors.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ERRORS_H_ -#define ERRORS_H_ - -#include - -#define E_OK 0 - -typedef int32 Error; - -#define E_ISOK(e) ((e) == (E_OK)) - -#endif // ERRORS_H_ diff --git a/kernel/extconf/extra.mk b/kernel/extconf/extra.mk new file mode 100644 index 0000000..b3fe8bc --- /dev/null +++ b/kernel/extconf/extra.mk @@ -0,0 +1 @@ +CFLAGS += -DKPRINTF_COLORS diff --git a/kernel/hal/hal.h b/kernel/hal/hal.h new file mode 100644 index 0000000..337ccbe --- /dev/null +++ b/kernel/hal/hal.h @@ -0,0 +1,19 @@ +#ifndef KERNEL_HAL_HAL_H_ +#define KERNEL_HAL_HAL_H_ + +#include + +#include "util.h" + +__attribute__((noreturn)) void hal_hang(void); + +void hal_init(void); +void hal_intr_disable(void); +void hal_intr_enable(void); +void hal_memset(void *mem, uint8_t v, uint32_t size); + +#if defined(__x86_64__) +# define HAL_PAGE_SIZE 0x1000 +#endif + +#endif // KERNEL_HAL_HAL_H_ diff --git a/kernel/hal/util.c b/kernel/hal/util.c new file mode 100644 index 0000000..0bbe093 --- /dev/null +++ b/kernel/hal/util.c @@ -0,0 +1,9 @@ +#include +#include "hal.h" + +void hal_memset(void *mem, uint8_t v, uint32_t size) { + uint8_t *mem1 = mem; + for (uint32_t i = 0; i < size; i++) { + mem1[i] = v; + } +} diff --git a/kernel/hal/util.h b/kernel/hal/util.h new file mode 100644 index 0000000..ef2a3c8 --- /dev/null +++ b/kernel/hal/util.h @@ -0,0 +1,6 @@ +#ifndef HAL_UTIL_H_ +#define HAL_UTIL_H_ + +#define HAL_MEMSET(m, v, n) hal_memset((void *)(m), (v), (n)) + +#endif // HAL_UTIL_H_ diff --git a/kernel/hal/x86_64/gdt.c b/kernel/hal/x86_64/gdt.c new file mode 100644 index 0000000..e3d8d3d --- /dev/null +++ b/kernel/hal/x86_64/gdt.c @@ -0,0 +1,94 @@ +#include +#include +#include "compiler/attr.h" +#include "hal/hal.h" + +#define GDT_SIZE 5 + +typedef struct { + uint16_t limitlow; + uint16_t baselow; + uint8_t basemid; + uint8_t access; + uint8_t gran; + uint8_t basehigh; +} PACKED GdtEntry; + +typedef struct { + uint16_t limit; + uint64_t base; +} PACKED GdtPtr; + +typedef struct { + GdtEntry old[5]; + GdtEntry tsslow; + GdtEntry tsshigh; +} PACKED ExtendedGdt; + +typedef struct { + uint32_t resv0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t resv1; + uint64_t ist[7]; + uint64_t resv2; + uint16_t resv3; + uint16_t iopb_off; +} PACKED Tss; + +static Tss tss = {0}; +static ExtendedGdt *curgdt = NULL; + +#define KCODE 0x08 +#define KDATA 0x10 +#define UCODE 0x18 +#define UDATA 0x20 +#define TSS 0x28 + +#define GDT_PRESENT 0x80 +#define GDT_TSS 0x89 + +static uint64_t gdt_curretbase(void) { + GdtPtr gdtr; + asm volatile("sgdt %0" : "=m"(gdtr)); + return gdtr.base; +} + +void gdt_setenty(GdtEntry *entry, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + entry->baselow = base & 0xffff; + entry->basemid = (base >> 16) & 0xff; + entry->basehigh = (base >> 24) & 0xff; + entry->limitlow = limit & 0xffff; + entry->gran = (limit >> 16) & 0x0f | (gran & 0xf0); + entry->access = access; +} + +void gdt_init(void) { + uint64_t base = gdt_curretbase(); + curgdt = (ExtendedGdt *)base; + + HAL_MEMSET(&tss, 0, sizeof(tss)); + tss.iopb_off = sizeof(tss); + + uint64_t tss_base = (uint64_t)&tss; + uint32_t tss_limit = sizeof(tss) - 1; + + gdt_setenty(&curgdt->tsslow, tss_base & 0xFFFFFFFF, tss_limit, GDT_PRESENT | GDT_TSS, 0x0); + + GdtEntry *tsshigh = &curgdt->tsshigh; + tsshigh->baselow = (tss_base >> 32) & 0xffff; + tsshigh->basemid = (tss_base >> 48) & 0xff; + tsshigh->basehigh = (tss_base >> 56) & 0xff; + tsshigh->access = 0; + tsshigh->gran = 0; + tsshigh->limitlow = 0; + + GdtPtr gdtr; + asm volatile("sgdt %0" : "=m"(gdtr)); + gdtr.limit = sizeof(ExtendedGdt) - 1; + asm volatile("lgdt %0" :: "m"(gdtr)); + + asm volatile("ltr %0" :: "r"((uint16_t)0x28)); +} + diff --git a/kernel/hal/x86_64/gdt.h b/kernel/hal/x86_64/gdt.h new file mode 100644 index 0000000..529a124 --- /dev/null +++ b/kernel/hal/x86_64/gdt.h @@ -0,0 +1,6 @@ +#ifndef HAL_GDT_H_ +#define HAL_GDT_H_ + +void gdt_init(void); + +#endif // HAL_GDT_H_ diff --git a/kernel/hal/x86_64/hal.c b/kernel/hal/x86_64/hal.c new file mode 100644 index 0000000..e22123c --- /dev/null +++ b/kernel/hal/x86_64/hal.c @@ -0,0 +1,21 @@ +#include +#include +#include "hal/hal.h" +#include "kprintf.h" +#include "serial.h" +#include "gdt.h" + +void hal_init(void) { + if (!serial_init()) { + hal_hang(); // going further makes no sense + } + LOG("hal", "serial init\n"); + gdt_init(); +} + +__attribute__((noreturn)) void hal_hang(void) { + for(;;) { + asm("hlt"); + } +} + diff --git a/kernel/hal/x86_64/intr.S b/kernel/hal/x86_64/intr.S new file mode 100644 index 0000000..520b0eb --- /dev/null +++ b/kernel/hal/x86_64/intr.S @@ -0,0 +1,9 @@ +.global hal_intr_enable +hal_intr_enable: + sti + ret + +.global hal_intr_disable +hal_intr_disable: + cli + ret diff --git a/kernel/hal/x86_64/serial.c b/kernel/hal/x86_64/serial.c new file mode 100644 index 0000000..f22f6aa --- /dev/null +++ b/kernel/hal/x86_64/serial.c @@ -0,0 +1,50 @@ +#include +#include + +#define SERIAL_PORT 0x3f8 + +extern uint8_t serial_inb(uint16_t port); +extern void serial_outb(uint16_t port, uint8_t value); + +static int serial_received(void) { + return serial_inb(SERIAL_PORT + 5) & 1; +} + +static uint8_t serial_read(void) { + while (serial_received() == 0); + return serial_inb(SERIAL_PORT); +} + +static int serial_trans_empty(void) { + return serial_inb(SERIAL_PORT + 5) & 0x20; +} + +static void serial_write(uint8_t value) { + while (!serial_trans_empty()); + serial_outb(SERIAL_PORT, value); +} + +// REFERENCE: https://wiki.osdev.org/Serial_Ports +bool serial_init(void) { + serial_outb(SERIAL_PORT + 1, 0x00); + serial_outb(SERIAL_PORT + 3, 0x80); + serial_outb(SERIAL_PORT + 0, 0x03); + serial_outb(SERIAL_PORT + 1, 0x00); + serial_outb(SERIAL_PORT + 3, 0x03); + serial_outb(SERIAL_PORT + 2, 0xc7); + serial_outb(SERIAL_PORT + 4, 0x0b); + serial_outb(SERIAL_PORT + 4, 0x1e); + serial_outb(SERIAL_PORT + 0, 0xae); + + if (serial_inb(SERIAL_PORT + 0) != 0xae) { + return false; + } + + serial_outb(SERIAL_PORT + 4, 0x0f); + return true; +} + +// For printf library +void putchar_(char c) { + serial_write(c); +} diff --git a/kernel/hal/x86_64/serial.h b/kernel/hal/x86_64/serial.h new file mode 100644 index 0000000..9eaba89 --- /dev/null +++ b/kernel/hal/x86_64/serial.h @@ -0,0 +1,8 @@ +#ifndef HAL_SERIAL_H_ +#define HAL_SERIAL_H_ + +#include + +bool serial_init(void); + +#endif // HAL_SERIAL_H_ diff --git a/kernel/hal/x86_64/serial1.S b/kernel/hal/x86_64/serial1.S new file mode 100644 index 0000000..689b5bb --- /dev/null +++ b/kernel/hal/x86_64/serial1.S @@ -0,0 +1,13 @@ +.global serial_outb +serial_outb: + mov %di, %dx + mov %sil, %al + out %al, %dx + ret + +.global serial_inb +serial_inb: + mov %di, %dx + in %dx, %al + movzx %al, %rax + ret diff --git a/kernel/kmain.c b/kernel/kmain.c index 1af376e..7fddd12 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,42 +1,22 @@ #include -#include -#include - -// Halt and catch fire function. -static void hcf(void) { - for (;;) { - asm ("hlt"); - } -} - -__attribute__((used, section(".limine_requests"))) -static volatile LIMINE_BASE_REVISION(3); - -__attribute__((used, section(".limine_requests_start"))) -static volatile LIMINE_REQUESTS_START_MARKER; - -__attribute__((used, section(".limine_requests_end"))) -static volatile LIMINE_REQUESTS_END_MARKER; - -__attribute__((used, section(".limine_requests"))) -static volatile struct limine_memmap_request memmap_request = { - .id = LIMINE_MEMMAP_REQUEST, - .revision = 0, -}; - -void limine_init(void) { - - if (LIMINE_BASE_REVISION_SUPPORTED == false) { - hcf(); - } -} +#include "kprintf.h" +#include "banner.h" +#include "hal/hal.h" +#include "bootinfo/bootinfo.h" +#include "pmm/pmm.h" +static volatile LIMINE_BASE_REVISION(2); void kmain(void) { - limine_init(); - com1_init(); + if (LIMINE_BASE_REVISION_SUPPORTED == false) { + hal_hang(); + } - kprintf("Hello dupa!\n"); + bootinfo_init(); + pmm_init(); + hal_init(); - hcf(); + kprintf(BANNER_TEXT "\n"); + + hal_hang(); } diff --git a/kernel/kprintf.h b/kernel/kprintf.h index 9bfc64f..002dd1b 100644 --- a/kernel/kprintf.h +++ b/kernel/kprintf.h @@ -10,4 +10,18 @@ #define kvsnprintf vsnprintf_ #define kvprintf vprintf_ +#ifdef KPRINTF_COLORS +# include "ansi_colors.h" +# define LOG(component, fmt, ...) kprintf(CRESET "[" CYN component CRESET "]: " fmt, ##__VA_ARGS__) +#else +# define LOG(component, fmt, ...) kprintf("["component"]: "fmt, ##__VA_ARGS__) +#endif + +#ifdef KPRINTF_COLORS +# include "ansi_colors.h" +# define ERR(component, fmt, ...) kprintf(CRESET "[" RED component CRESET "]: " fmt, ##__VA_ARGS__) +#else +# define ERR(component, fmt, ...) kprintf("["component"]: "fmt, ##__VA_ARGS__) +#endif + #endif // KPRINTF_H_ diff --git a/kernel/pmm/pmm.c b/kernel/pmm/pmm.c new file mode 100644 index 0000000..0516593 --- /dev/null +++ b/kernel/pmm/pmm.c @@ -0,0 +1,71 @@ +#include +#include +#include "pmm.h" +#include "spinlock.h" +#include "kprintf.h" +#include "bitmap/bitmap.h" +#include "bootinfo/bootinfo.h" + +#define _DIV_ROUNDUP(num, div) ((num + div - 1) / div) + +PhysMem PHYS_MEM; + +void pmm_init(void) { + PHYS_MEM.spinlock = SPINLOCK_INIT(); + + BitMap *bm = &PHYS_MEM.self; + bm->init = false; + + bm->nblocks = _DIV_ROUNDUP(BOOT_INFO.memmap_total, BITMAP_BLOCK_SIZE); + bm->nbytes = _DIV_ROUNDUP(bm->nblocks, 8); + + struct limine_memmap_entry *memmap_ent = NULL; + + for (size_t i = 0; i < BOOT_INFO.memmap_entrycount; i++) { + struct limine_memmap_entry *entry = BOOT_INFO.memmap_entries[i]; + if (entry->type != LIMINE_MEMMAP_USABLE || entry->length < bm->nbytes) { + continue; + } + memmap_ent = entry; + break; + } + + if (!memmap_ent) { + ERR("hal/pmm", "required memory: {%lx}\n", bm->nbytes); + hal_hang(); + } + + size_t physbegin = memmap_ent->base; + bm->map = (uint8_t *)(physbegin + BOOT_INFO.hhdm_off); + + HAL_MEMSET(bm->map, 0xff, bm->nbytes); + for (size_t i = 0; i < BOOT_INFO.memmap_entrycount; i++) { + struct limine_memmap_entry *entry = BOOT_INFO.memmap_entries[i]; + // mark usable as 0 and unusable as 1 + bitmap_markregion(bm, (void *)entry->base, entry->length, entry->type != LIMINE_MEMMAP_USABLE); + } + + bitmap_markregion(bm, (void *)physbegin, bm->nbytes, 1); + bm->alloc_blocks = 0; + + LOG("hal/pmm", "phys bitmap init 0x%lx, size = 0x%lx\n", physbegin, bm->nbytes); + bm->init = true; +} + +void *pmm_alloc(size_t pages) { + SPINLOCK_ACQUIRE(&PHYS_MEM.spinlock); + uintptr_t phys = (uintptr_t)bitmap_alloc(&PHYS_MEM.self, pages); + SPINLOCK_RELEASE(&PHYS_MEM.spinlock); + + if (!phys) { + ERR("hal/pmm", "phys memory ran out\n"); + hal_hang(); + } + return (void *)phys; +} + +void pmm_free(uintptr_t ptr, size_t pages) { + SPINLOCK_ACQUIRE(&PHYS_MEM.spinlock); + bitmap_markregion(&PHYS_MEM.self, (void *)ptr, pages * BITMAP_BLOCK_SIZE, 0); + SPINLOCK_RELEASE(&PHYS_MEM.spinlock); +} diff --git a/kernel/pmm/pmm.h b/kernel/pmm/pmm.h new file mode 100644 index 0000000..005cd25 --- /dev/null +++ b/kernel/pmm/pmm.h @@ -0,0 +1,20 @@ +#ifndef PMM_PMM_H_ +#define PMM_PMM_H_ + +#include +#include +#include "spinlock.h" +#include "bitmap/bitmap.h" + +typedef struct { + SpinLock spinlock; + BitMap self; +} PhysMem; + +extern PhysMem PHYS_MEM; + +void pmm_init(void); +void *pmm_alloc(size_t pages); +void pmm_free(uintptr_t ptr, size_t pages); + +#endif // PMM_PMM_H_ diff --git a/kernel/serial.asm b/kernel/serial.asm deleted file mode 100644 index 0248607..0000000 --- a/kernel/serial.asm +++ /dev/null @@ -1,14 +0,0 @@ -global serial_outb -serial_outb: - mov dx, di - mov al, sil - out dx, al - ret - -global serial_inb -serial_inb: - mov dx, di - in al, dx - movzx rax, al - ret - diff --git a/kernel/serial.h b/kernel/serial.h deleted file mode 100644 index 3a500cf..0000000 --- a/kernel/serial.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SERIAL_H_ -#define SERIAL_H_ - -#include - -void serial_outb(uint16 port, uint8 value); -uint8 serial_inb(uint16 port); - -#endif // SERIAL_H_ diff --git a/kernel/spinlock.h b/kernel/spinlock.h new file mode 100644 index 0000000..5ee2b72 --- /dev/null +++ b/kernel/spinlock.h @@ -0,0 +1,31 @@ +#ifndef SPINLOCK_SPINLOCK_H_ +#define SPINLOCK_SPINLOCK_H_ + +#include +#include "hal/hal.h" + +typedef atomic_bool SpinLock; + +// Spin more efficiently - cpu dependant +#if defined(__x86_64__) +# define SPINLOCK_HINT() asm volatile("pause") +#else +# define SPINLOCK_HINT() +#endif + +#define SPINLOCK_ACQUIRE(sl) \ + do { \ + bool __unlocked = false; \ + while (!atomic_compare_exchange_weak((sl), &__unlocked, true)) { \ + SPINLOCK_HINT(); \ + } \ + } while(0) + +#define SPINLOCK_RELEASE(sl) \ + do { \ + atomic_store((sl), false); \ + } while(0) + +#define SPINLOCK_INIT() false + +#endif // SPINLOCK_SPINLOCK_H_ diff --git a/kernel/types.h b/kernel/types.h deleted file mode 100644 index 669a3cf..0000000 --- a/kernel/types.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TYPES_H_ -#define TYPES_H_ - -#define NULL ((void *)0) - -typedef char int8; -typedef unsigned char uint8; -typedef short int16; -typedef unsigned short uint16; -typedef int int32; -typedef unsigned int uint32; -typedef long long int64; -typedef unsigned long long uint64; - -#endif // TYPES_H_ diff --git a/run/qemu-x86_64.sh b/run/qemu-x86_64.sh new file mode 100755 index 0000000..06732c6 --- /dev/null +++ b/run/qemu-x86_64.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +qemu-system-x86_64 -m 4g -cdrom mop2.iso -boot d -serial stdio $@