From 15e808a0013b29c38b405b9fd16fae12717b9c38 Mon Sep 17 00:00:00 2001 From: SpookyDervish Date: Tue, 14 Jul 2026 08:46:22 +1000 Subject: [PATCH] i change my mind we're going limine --- .gitignore | 9 +- GNUmakefile | 166 +++++++++ Makefile | 77 ----- get_limine.sh | 5 + iso.sh | 0 limine.conf | 10 + linker.ld | 36 -- linker.lds | 76 +++++ src/boot/loader.S | 31 -- src/include/multiboot.h | 125 ------- src/kernel/common/memory.c | 52 +++ src/kernel/common/memory.h | 14 + src/kernel/kernel.c | 70 ++++ src/kernel/kernel.cpp | 18 - src/kernel/limine.h | 669 +++++++++++++++++++++++++++++++++++++ src/kernel/vga_console.cpp | 13 - src/kernel/vga_console.h | 3 - 17 files changed, 1067 insertions(+), 307 deletions(-) create mode 100644 GNUmakefile delete mode 100644 Makefile create mode 100644 get_limine.sh create mode 100755 iso.sh create mode 100644 limine.conf delete mode 100644 linker.ld create mode 100644 linker.lds delete mode 100644 src/boot/loader.S delete mode 100644 src/include/multiboot.h create mode 100644 src/kernel/common/memory.c create mode 100644 src/kernel/common/memory.h create mode 100644 src/kernel/kernel.c delete mode 100644 src/kernel/kernel.cpp create mode 100644 src/kernel/limine.h delete mode 100644 src/kernel/vga_console.cpp delete mode 100644 src/kernel/vga_console.h diff --git a/.gitignore b/.gitignore index 5fa52b0..3109501 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -CometOS.bin -CometOS.iso -build/ -iso/ \ No newline at end of file +bin/ +iso_root/ +limine-binary/ +obj/ +CometOS.iso \ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..eb768de --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,166 @@ +# Nuke built-in rules. +.SUFFIXES: + +# This is the name that our final executable will have. +# Change as needed. +override OUTPUT := CometOS + +# User controllable toolchain and toolchain prefix. +TOOLCHAIN := +TOOLCHAIN_PREFIX := +ifneq ($(TOOLCHAIN),) + ifeq ($(TOOLCHAIN_PREFIX),) + TOOLCHAIN_PREFIX := $(TOOLCHAIN)- + endif +endif + +# User controllable C compiler command. +ifneq ($(TOOLCHAIN_PREFIX),) + CC := $(TOOLCHAIN_PREFIX)gcc +else + CC := cc +endif + +# User controllable linker command. +LD := $(TOOLCHAIN_PREFIX)ld + +# Defaults overrides for variables if using "llvm" as toolchain. +ifeq ($(TOOLCHAIN),llvm) + CC := clang + LD := ld.lld +endif + +# User controllable C flags. +CFLAGS := -g -O2 -pipe + +# User controllable C preprocessor flags. We set none by default. +CPPFLAGS := + +# User controllable nasm flags. +NASMFLAGS := -g + +# User controllable linker flags. We set none by default. +LDFLAGS := + +# Check if CC is Clang. +override CC_IS_CLANG := $(shell ! $(CC) --version 2>/dev/null | grep -q '^Target: '; echo $$?) + +# If the C compiler is Clang, set the target as needed. +ifeq ($(CC_IS_CLANG),1) + override CC += \ + -target x86_64-unknown-none-elf +endif + +# Internal C flags that should not be changed by the user. +override CFLAGS += \ + -Wall \ + -Wextra \ + -std=gnu11 \ + -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 + +# Internal C preprocessor flags that should not be changed by the user. +override CPPFLAGS := \ + -I src \ + $(CPPFLAGS) \ + -MMD \ + -MP + +# Internal nasm flags that should not be changed by the user. +override NASMFLAGS := \ + -f elf64 \ + $(patsubst -g,-g -F dwarf,$(NASMFLAGS)) \ + -Wall + +# Internal linker flags that should not be changed by the user. +override LDFLAGS += \ + -m elf_x86_64 \ + -nostdlib \ + -static \ + -z max-page-size=0x1000 \ + --gc-sections \ + -T linker.lds + +# Use "find" to glob all *.c, *.S, and *.asm files in the tree and obtain the +# object and header dependency file names. +override SRCFILES := $(shell find -L src -type f 2>/dev/null | LC_ALL=C sort) +override CFILES := $(filter %.c,$(SRCFILES)) +override ASFILES := $(filter %.S,$(SRCFILES)) +override NASMFILES := $(filter %.asm,$(SRCFILES)) +override OBJ := $(addprefix obj/,$(CFILES:.c=.c.o) $(ASFILES:.S=.S.o) $(NASMFILES:.asm=.asm.o)) +override HEADER_DEPS := $(addprefix obj/,$(CFILES:.c=.c.d) $(ASFILES:.S=.S.d)) + +# Default target. This must come first, before header dependencies. +.PHONY: all +all: bin/$(OUTPUT) + +# Include header dependencies. +-include $(HEADER_DEPS) + +# Link rules for the final executable. +bin/$(OUTPUT): GNUmakefile linker.lds $(OBJ) + mkdir -p "$(dir $@)" + $(LD) $(LDFLAGS) $(OBJ) -o $@ + +# Compilation rules for *.c files. +obj/%.c.o: %.c GNUmakefile + mkdir -p "$(dir $@)" + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +# Compilation rules for *.S files. +obj/%.S.o: %.S GNUmakefile + mkdir -p "$(dir $@)" + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +# Compilation rules for *.asm (nasm) files. +obj/%.asm.o: %.asm GNUmakefile + mkdir -p "$(dir $@)" + nasm $(NASMFLAGS) $< -o $@ + +# Remove object files and the final executable. +.PHONY: clean iso +clean: + rm -rf bin obj + +iso: bin/$(OUTPUT) + # Create a directory which will be our ISO root. + mkdir -p iso_root + + # Copy the relevant files over. + mkdir -p iso_root/boot + cp -v bin/CometOS iso_root/boot/ + mkdir -p iso_root/boot/limine + cp -v limine.conf limine-binary/limine-bios.sys limine-binary/limine-bios-cd.bin \ + limine-binary/limine-uefi-cd.bin iso_root/boot/limine/ + + # Create the EFI boot tree and copy Limine's EFI executables over. + mkdir -p iso_root/EFI/BOOT + cp -v limine-binary/BOOTX64.EFI iso_root/EFI/BOOT/ + cp -v limine-binary/BOOTIA32.EFI iso_root/EFI/BOOT/ + + # Create the bootable ISO. + 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 CometOS.iso + + # Install Limine stage 1 and 2 for legacy BIOS boot. + ./limine-binary/limine bios-install CometOS.iso + +run: iso + qemu-system-x86_64 -cdrom CometOS.iso -m 1024 \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index c19ce09..0000000 --- a/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# ============================================================================== -# 1. PROJECT CONFIGURATION -# ============================================================================== -BIN_TARGET := CometOS.bin -TARGET := CometOS.iso -BUILD_DIR := build -LDSCRIPT := linker.ld - -# Toolchain definitions -CXX := g++ -ASM := as -LD := ld - -# Compiler and Linker Flags -ASMFLAGS := --32 -CXXFLAGS := -Wall -Wextra -O3 -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -LDFLAGS := -T $(LDSCRIPT) -melf_i386 - -# ============================================================================== -# 2. FILE SEARCH AND COMPONENT SETUP -# ============================================================================== -# Find all source files recursively in the current folder and subfolders -SRCS := $(wildcard src/**/*.cpp src/**/*.S) - -# Strip paths and convert extensions to .o (e.g., "src/main.cpp" -> "main.o") -RAW_OBJS := $(patsubst %.cpp,%.o,$(patsubst %.S,%.o,$(notdir $(SRCS)))) - -# Place all object files into the build directory -OBJS := $(addprefix $(BUILD_DIR)/, $(RAW_OBJS)) - -# Automagically tell Make where to find the original source files -VPATH := $(sort $(dir $(SRCS))) - -# ============================================================================== -# 3. BUILD RULES -# ============================================================================== -.PHONY: all clean run - -# Default rule -all: $(TARGET) - -run: $(TARGET) - qemu-system-i386 -cdrom $(TARGET) -m 1024 - -# Link rule: Combines all objects using the linker script -$(BIN_TARGET): $(OBJS) $(LDSCRIPT) - $(LD) $(OBJS) $(LDFLAGS) -o $@ - @echo "Build successful: $(BIN_TARGET)" - -$(TARGET): $(BIN_TARGET) - @mkdir iso/boot/grub -p - @cp $< iso/boot/ - @echo 'set default=0' > iso/boot/grub/grub.cfg - @echo 'set timeout=0' >> iso/boot/grub/grub.cfg - @echo '' >> iso/boot/grub/grub.cfg - @echo 'menuentry "CometOS" {' >> iso/boot/grub/grub.cfg - @echo ' multiboot /boot/CometOS.bin' >> iso/boot/grub/grub.cfg - @echo ' boot' >> iso/boot/grub/grub.cfg - @echo '}' >> iso/boot/grub/grub.cfg - grub-mkrescue --output=$@ iso - -# Compilation rule for C++ files -$(BUILD_DIR)/%.o: %.cpp | $(BUILD_DIR) - $(CXX) $(CXXFLAGS) -c $< -o $@ - -# Compilation rule for Assembly files -$(BUILD_DIR)/%.o: %.S | $(BUILD_DIR) - $(ASM) $(ASMFLAGS) -c $< -o $@ - -# Safely create the build directory if it doesn't exist -$(BUILD_DIR): - mkdir -p $(BUILD_DIR) - -# Cleanup rule -clean: - rm -rf $(BUILD_DIR) $(BIN_TARGET) $(TARGET) - @echo "Cleaned up build files." diff --git a/get_limine.sh b/get_limine.sh new file mode 100644 index 0000000..71b8b41 --- /dev/null +++ b/get_limine.sh @@ -0,0 +1,5 @@ +# Download the latest Limine binary release. +curl -L https://github.com/Limine-Bootloader/Limine/releases/latest/download/limine-binary.tar.gz | gunzip | tar -xf - + +# Build "limine" utility. +make -C limine-binary \ No newline at end of file diff --git a/iso.sh b/iso.sh new file mode 100755 index 0000000..e69de29 diff --git a/limine.conf b/limine.conf new file mode 100644 index 0000000..1e62a6d --- /dev/null +++ b/limine.conf @@ -0,0 +1,10 @@ +# Timeout in seconds that Limine will use before automatically booting. +timeout: 5 + +# The entry name that will be displayed in the boot menu. +/CometOS + # We use the Limine boot protocol. + protocol: limine + + # Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located. + path: boot():/boot/CometOS diff --git a/linker.ld b/linker.ld deleted file mode 100644 index a4a68d7..0000000 --- a/linker.ld +++ /dev/null @@ -1,36 +0,0 @@ -ENTRY(loader) -OUTPUT_FORMAT(elf32-i386) -OUTPUT_ARCH(i386:i386) - -SECTIONS -{ - . = 0x0100000; - - .text : - { - *(.multiboot) - *(.text*) - *(.rodata) - } - - .data : - { - start_ctors = .; - KEEP(*( .init_array )); - KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))) - end_ctors = .; - - *(.data) - } - - .bss : - { - *(.bss) - } - - /DISCARD/ : - { - *(.fini_array*) - *(.comment) - } -} \ No newline at end of file diff --git a/linker.lds b/linker.lds new file mode 100644 index 0000000..1a93cb2 --- /dev/null +++ b/linker.lds @@ -0,0 +1,76 @@ + + +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) + +/* We want the symbol kmain 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. */ +PHDRS +{ + limine_requests PT_LOAD; + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to 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)); + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Add a .note.gnu.build-id output section in case a build ID flag is added to the */ + /* linker command. */ + .note.gnu.build-id : { + *(.note.gnu.build-id) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + } :data + + /* 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 */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} diff --git a/src/boot/loader.S b/src/boot/loader.S deleted file mode 100644 index 62abeab..0000000 --- a/src/boot/loader.S +++ /dev/null @@ -1,31 +0,0 @@ -.set MAGIC, 0x1badb002 -.set FLAGS, (1<<0 | 1<<1) -.set CHECKSUM, -(MAGIC + FLAGS) - -.section .multiboot - .long MAGIC - .long FLAGS - .long CHECKSUM - -.section .text -.extern kernelMain -.extern callConstructors -.global loader - -loader: - mov $kernel_stack, %esp - - call callConstructors - - push %eax - push %ebx - call kernelMain - -_stop: # should never actually reach this but just in case... - cli - hlt - jmp _stop - -.section .bss -.space 2*1024*1024 # Give the kernel 2MB of stack space -kernel_stack: diff --git a/src/include/multiboot.h b/src/include/multiboot.h deleted file mode 100644 index bf9fed9..0000000 --- a/src/include/multiboot.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef MULTIBOOT_H -#define MULTIBOOT_H -// The following was copied from https://www.gnu.org/software/grub/manual/multiboot/html_node/multiboot.h.html - -/* multiboot.h - the header for Multiboot */ -/* Copyright (C) 1999, 2001 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* Macros. */ - -/* The magic number for the Multiboot header. */ -#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 - -/* The flags for the Multiboot header. */ -#ifdef __ELF__ -# define MULTIBOOT_HEADER_FLAGS 0x00000003 -#else -# define MULTIBOOT_HEADER_FLAGS 0x00010003 -#endif - -/* The magic number passed by a Multiboot-compliant boot loader. */ -#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 - -/* The size of our stack (16KB). */ -#define STACK_SIZE 0x4000 - -/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ -#ifdef HAVE_ASM_USCORE -# define EXT_C(sym) _ ## sym -#else -# define EXT_C(sym) sym -#endif - -#ifndef ASM -/* Do not include here in boot.S. */ - -/* Types. */ - -/* The Multiboot header. */ -typedef struct multiboot_header -{ - unsigned long magic; - unsigned long flags; - unsigned long checksum; - unsigned long header_addr; - unsigned long load_addr; - unsigned long load_end_addr; - unsigned long bss_end_addr; - unsigned long entry_addr; -} multiboot_header_t; - -/* The symbol table for a.out. */ -typedef struct aout_symbol_table -{ - unsigned long tabsize; - unsigned long strsize; - unsigned long addr; - unsigned long reserved; -} aout_symbol_table_t; - -/* The section header table for ELF. */ -typedef struct elf_section_header_table -{ - unsigned long num; - unsigned long size; - unsigned long addr; - unsigned long shndx; -} elf_section_header_table_t; - -/* The Multiboot information. */ -typedef struct multiboot_info -{ - unsigned long flags; - unsigned long mem_lower; - unsigned long mem_upper; - unsigned long boot_device; - unsigned long cmdline; - unsigned long mods_count; - unsigned long mods_addr; - union - { - aout_symbol_table_t aout_sym; - elf_section_header_table_t elf_sec; - } u; - unsigned long mmap_length; - unsigned long mmap_addr; -} multiboot_info_t; - -/* The module structure. */ -typedef struct module -{ - unsigned long mod_start; - unsigned long mod_end; - unsigned long string; - unsigned long reserved; -} module_t; - -/* The memory map. Be careful that the offset 0 is base_addr_low - but no size. */ -typedef struct memory_map -{ - unsigned long size; - unsigned long base_addr_low; - unsigned long base_addr_high; - unsigned long length_low; - unsigned long length_high; - unsigned long type; -} memory_map_t; - -#endif /* ! ASM */ - -#endif /* MULTIBOOT_H */ \ No newline at end of file diff --git a/src/kernel/common/memory.c b/src/kernel/common/memory.c new file mode 100644 index 0000000..b53ad62 --- /dev/null +++ b/src/kernel/common/memory.c @@ -0,0 +1,52 @@ +#include "memory.h" + +void *memcpy(void *restrict dest, const void *restrict src, size_t n) { + uint8_t *restrict pdest = dest; + const uint8_t *restrict psrc = src; + + for (size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } + + return dest; +} + +void *memset(void *s, int c, size_t n) { + uint8_t *p = s; + + for (size_t i = 0; i < n; i++) { + p[i] = (uint8_t)c; + } + + return s; +} + +void *memmove(void *dest, const void *src, size_t n) { + uint8_t *pdest = dest; + const uint8_t *psrc = src; + + if ((uintptr_t)src > (uintptr_t)dest) { + for (size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } + } else if ((uintptr_t)src < (uintptr_t)dest) { + for (size_t i = n; i > 0; i--) { + pdest[i-1] = psrc[i-1]; + } + } + + return dest; +} + +int memcmp(const void *s1, const void *s2, size_t n) { + const uint8_t *p1 = s1; + const uint8_t *p2 = s2; + + for (size_t i = 0; i < n; i++) { + if (p1[i] != p2[i]) { + return p1[i] < p2[i] ? -1 : 1; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/kernel/common/memory.h b/src/kernel/common/memory.h new file mode 100644 index 0000000..bbf6290 --- /dev/null +++ b/src/kernel/common/memory.h @@ -0,0 +1,14 @@ +#include +#include + + +// GCC and Clang reserve the right to generate calls to the following +// 4 functions even if they are not directly called. +// Implement them as the C specification mandates. +// DO NOT remove or rename these functions, or stuff will eventually break! +// They CAN be moved to a different .c file. + +void *memcpy(void *restrict dest, const void *restrict src, size_t n); +void *memset(void *s, int c, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c new file mode 100644 index 0000000..40c33c4 --- /dev/null +++ b/src/kernel/kernel.c @@ -0,0 +1,70 @@ +#include +#include +#include "limine.h" +#include "common/memory.h" + +// Set the base revision to 6, this is recommended as this is the latest +// base revision described by the Limine boot protocol specification. +// See specification for further info. + +__attribute__((used, section(".limine_requests"))) +static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(6); + +// The Limine requests can be placed anywhere, but it is important that +// the compiler does not optimise them away, so, usually, they should +// be made volatile or equivalent, _and_ they should be accessed at least +// once or marked as used with the "used" attribute as done here. + +__attribute__((used, section(".limine_requests"))) +static volatile struct limine_framebuffer_request framebuffer_request = { + .id = LIMINE_FRAMEBUFFER_REQUEST_ID, + .revision = 0 +}; + +// Finally, define the start and end markers for the Limine requests. +// These can also be moved anywhere, to any .c file, as seen fit. + +__attribute__((used, section(".limine_requests_start"))) +static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER; + +__attribute__((used, section(".limine_requests_end"))) +static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER; + +static void everythingsDying(void) { + while (1) { + asm ("hlt"); + } +} + +// The following will be our kernel's entry point. +// If renaming kmain() to something else, make sure to change the +// linker script accordingly. +void kmain(void) { + // Ensure the bootloader actually understands our base revision (see spec). + if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { + everythingsDying(); + } + + // Ensure we got a framebuffer. + if (framebuffer_request.response == NULL + || framebuffer_request.response->framebuffer_count < 1) { + everythingsDying(); + } + + // Fetch the first framebuffer. + struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0]; + + // Print a nice pattern to screen as an example. + // Note: we assume the framebuffer model is RGB with 32-bit pixels. + volatile uint32_t *fb_ptr = framebuffer->address; + for (size_t y = 0; y < framebuffer->height; y++) { + for (size_t x = 0; x < framebuffer->width; x++) { + uint32_t nX = x * 255 / framebuffer->width; + uint32_t nY = y * 255 / framebuffer->height; + fb_ptr[y * (framebuffer->pitch / 4) + x] = (nY << 8) | nX; + } + } + + // We're done, just hang... + everythingsDying(); +} \ No newline at end of file diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp deleted file mode 100644 index 106c5d2..0000000 --- a/src/kernel/kernel.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "../include/multiboot.h" -#include "vga_console.h" - -typedef void(*constructor)(); -extern "C" constructor start_ctors; -extern "C" constructor end_ctors; -extern "C" void callConstructors() -{ - for (constructor* i = &start_ctors; i != &end_ctors; i++) { - (*i)(); - } -} - -extern "C" void kernelMain(multiboot_info* multibootInfo, unsigned int magicNumber) { - vgaPrint("Hello, world!"); - - while (true); -} \ No newline at end of file diff --git a/src/kernel/limine.h b/src/kernel/limine.h new file mode 100644 index 0000000..693cb72 --- /dev/null +++ b/src/kernel/limine.h @@ -0,0 +1,669 @@ +/* SPDX-License-Identifier: 0BSD */ + +/* Copyright (C) 2022-2026 Mintsuki and contributors. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef LIMINE_H +#define LIMINE_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc */ + +#ifdef LIMINE_NO_POINTERS +# define LIMINE_PTR(TYPE) uint64_t +#else +# define LIMINE_PTR(TYPE) TYPE +#endif + +#define LIMINE_REQUESTS_START_MARKER { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \ + 0x785c6ed015d3e316, 0x181e920a7852b9d9 } +#define LIMINE_REQUESTS_END_MARKER { 0xadc0e0531bb10d03, 0x9572709f31764c62 } + +#define LIMINE_BASE_REVISION(N) { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) } + +#define LIMINE_BASE_REVISION_SUPPORTED(VAR) ((VAR)[2] == 0) + +#define LIMINE_LOADED_BASE_REVISION_VALID(VAR) ((VAR)[1] != 0x6a7b384944536bdc) +#define LIMINE_LOADED_BASE_REVISION(VAR) ((VAR)[1]) + +#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b + +struct limine_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; +}; + +#define LIMINE_MEDIA_TYPE_GENERIC 0 +#define LIMINE_MEDIA_TYPE_OPTICAL 1 +#define LIMINE_MEDIA_TYPE_TFTP 2 + +struct limine_file { + uint64_t revision; + LIMINE_PTR(void *) address; + uint64_t size; + LIMINE_PTR(char *) path; + LIMINE_PTR(char *) string; + uint32_t media_type; + uint32_t unused; + uint8_t tftp_ipv4[4]; + uint32_t tftp_port; + uint32_t partition_index; + uint32_t mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; +}; + +/* Boot info */ + +#define LIMINE_BOOTLOADER_INFO_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 } + +struct limine_bootloader_info_response { + uint64_t revision; + LIMINE_PTR(char *) name; + LIMINE_PTR(char *) version; +}; + +struct limine_bootloader_info_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_info_response *) response; +}; + +/* Executable command line */ + +#define LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a } + +struct limine_executable_cmdline_response { + uint64_t revision; + LIMINE_PTR(char *) cmdline; +}; + +struct limine_executable_cmdline_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_cmdline_response *) response; +}; + +/* Firmware type */ + +#define LIMINE_FIRMWARE_TYPE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 } + +#define LIMINE_FIRMWARE_TYPE_X86BIOS 0 +#define LIMINE_FIRMWARE_TYPE_EFI32 1 +#define LIMINE_FIRMWARE_TYPE_EFI64 2 +#define LIMINE_FIRMWARE_TYPE_SBI 3 + +struct limine_firmware_type_response { + uint64_t revision; + uint64_t firmware_type; +}; + +struct limine_firmware_type_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_firmware_type_response *) response; +}; + +/* Stack size */ + +#define LIMINE_STACK_SIZE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d } + +struct limine_stack_size_response { + uint64_t revision; +}; + +struct limine_stack_size_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_stack_size_response *) response; + uint64_t stack_size; +}; + +/* HHDM */ + +#define LIMINE_HHDM_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b } + +struct limine_hhdm_response { + uint64_t revision; + uint64_t offset; +}; + +struct limine_hhdm_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_hhdm_response *) response; +}; + +/* Framebuffer */ + +#define LIMINE_FRAMEBUFFER_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b } + +#define LIMINE_FRAMEBUFFER_RGB 1 + +struct limine_video_mode { + uint64_t pitch; + uint64_t width; + uint64_t height; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; +}; + +struct limine_framebuffer { + LIMINE_PTR(void *) address; + uint64_t width; + uint64_t height; + uint64_t pitch; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + uint8_t unused[7]; + uint64_t edid_size; + LIMINE_PTR(void *) edid; + /* Response revision 1 */ + uint64_t mode_count; + LIMINE_PTR(struct limine_video_mode **) modes; +}; + +struct limine_framebuffer_response { + uint64_t revision; + uint64_t framebuffer_count; + LIMINE_PTR(struct limine_framebuffer **) framebuffers; +}; + +struct limine_framebuffer_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_framebuffer_response *) response; +}; + +/* Flanterm FB init params */ + +#define LIMINE_FLANTERM_FB_INIT_PARAMS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3259399fe7c5f126, 0xe01c1c8c5db9d1a9 } + +#define LIMINE_FLANTERM_FB_ROTATE_0 0 +#define LIMINE_FLANTERM_FB_ROTATE_90 1 +#define LIMINE_FLANTERM_FB_ROTATE_180 2 +#define LIMINE_FLANTERM_FB_ROTATE_270 3 + +struct limine_flanterm_fb_init_params { + LIMINE_PTR(uint32_t *) canvas; + uint64_t canvas_size; + uint32_t ansi_colours[8]; + uint32_t ansi_bright_colours[8]; + uint32_t default_bg; + uint32_t default_fg; + uint32_t default_bg_bright; + uint32_t default_fg_bright; + LIMINE_PTR(void *) font; + uint64_t font_width; + uint64_t font_height; + uint64_t font_spacing; + uint64_t font_scale_x; + uint64_t font_scale_y; + uint64_t margin; + uint64_t rotation; +}; + +struct limine_flanterm_fb_init_params_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_flanterm_fb_init_params **) entries; +}; + +struct limine_flanterm_fb_init_params_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_flanterm_fb_init_params_response *) response; +}; + +/* Paging mode */ + +#define LIMINE_PAGING_MODE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a } + +#define LIMINE_PAGING_MODE_X86_64_4LVL 0 +#define LIMINE_PAGING_MODE_X86_64_5LVL 1 +#define LIMINE_PAGING_MODE_X86_64_MIN LIMINE_PAGING_MODE_X86_64_4LVL +#define LIMINE_PAGING_MODE_X86_64_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL + +#define LIMINE_PAGING_MODE_AARCH64_4LVL 0 +#define LIMINE_PAGING_MODE_AARCH64_5LVL 1 +#define LIMINE_PAGING_MODE_AARCH64_MIN LIMINE_PAGING_MODE_AARCH64_4LVL +#define LIMINE_PAGING_MODE_AARCH64_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL + +#define LIMINE_PAGING_MODE_RISCV_SV39 0 +#define LIMINE_PAGING_MODE_RISCV_SV48 1 +#define LIMINE_PAGING_MODE_RISCV_SV57 2 +#define LIMINE_PAGING_MODE_RISCV_MIN LIMINE_PAGING_MODE_RISCV_SV39 +#define LIMINE_PAGING_MODE_RISCV_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48 + +#define LIMINE_PAGING_MODE_LOONGARCH_4LVL 0 +#define LIMINE_PAGING_MODE_LOONGARCH_MIN LIMINE_PAGING_MODE_LOONGARCH_4LVL +#define LIMINE_PAGING_MODE_LOONGARCH_DEFAULT LIMINE_PAGING_MODE_LOONGARCH_4LVL + +struct limine_paging_mode_response { + uint64_t revision; + uint64_t mode; +}; + +struct limine_paging_mode_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_paging_mode_response *) response; + uint64_t mode; + uint64_t max_mode; + uint64_t min_mode; +}; + +/* MP */ + +#define LIMINE_MP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } + +struct limine_mp_info; + +typedef void (*limine_goto_address)(struct limine_mp_info *); + +#if defined (__x86_64__) || defined (__i386__) + +#define LIMINE_MP_RESPONSE_X86_64_X2APIC (1 << 0) + +struct limine_mp_info { + uint32_t processor_id; + uint32_t lapic_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint32_t flags; + uint32_t bsp_lapic_id; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__aarch64__) + +struct limine_mp_info { + uint32_t processor_id; + uint32_t reserved1; + uint64_t mpidr; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint64_t flags; + uint64_t bsp_mpidr; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__riscv) && (__riscv_xlen == 64) + +struct limine_mp_info { + uint64_t processor_id; + uint64_t hartid; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint64_t flags; + uint64_t bsp_hartid; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__loongarch__) && (__loongarch_grlen == 64) + +struct limine_mp_info { + uint64_t processor_id; + uint64_t phys_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint64_t flags; + uint64_t bsp_phys_id; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#else +#error Unknown architecture +#endif + +#define LIMINE_MP_REQUEST_X86_64_X2APIC (1 << 0) + +struct limine_mp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_mp_response *) response; + uint64_t flags; +}; + +/* Memory map */ + +#define LIMINE_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 } + +#define LIMINE_MEMMAP_USABLE 0 +#define LIMINE_MEMMAP_RESERVED 1 +#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 +#define LIMINE_MEMMAP_ACPI_NVS 3 +#define LIMINE_MEMMAP_BAD_MEMORY 4 +#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 +#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6 +#define LIMINE_MEMMAP_FRAMEBUFFER 7 +#define LIMINE_MEMMAP_RESERVED_MAPPED 8 + +struct limine_memmap_entry { + uint64_t base; + uint64_t length; + uint64_t type; +}; + +struct limine_memmap_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_memmap_entry **) entries; +}; + +struct limine_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_memmap_response *) response; +}; + +/* Entry point */ + +#define LIMINE_ENTRY_POINT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a } + +typedef void (*limine_entry_point)(void); + +struct limine_entry_point_response { + uint64_t revision; +}; + +struct limine_entry_point_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_entry_point_response *) response; + LIMINE_PTR(limine_entry_point) entry; +}; + +/* Executable File */ + +#define LIMINE_EXECUTABLE_FILE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } + +struct limine_executable_file_response { + uint64_t revision; + LIMINE_PTR(struct limine_file *) executable_file; +}; + +struct limine_executable_file_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_file_response *) response; +}; + +/* Module */ + +#define LIMINE_MODULE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee } + +#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0) +#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1) + +struct limine_internal_module { + LIMINE_PTR(const char *) path; + LIMINE_PTR(const char *) string; + uint64_t flags; +}; + +struct limine_module_response { + uint64_t revision; + uint64_t module_count; + LIMINE_PTR(struct limine_file **) modules; +}; + +struct limine_module_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_module_response *) response; + + /* Request revision 1 */ + uint64_t internal_module_count; + LIMINE_PTR(struct limine_internal_module **) internal_modules; +}; + +/* RSDP */ + +#define LIMINE_RSDP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c } + +struct limine_rsdp_response { + uint64_t revision; + LIMINE_PTR(void *) address; +}; + +struct limine_rsdp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_rsdp_response *) response; +}; + +/* SMBIOS */ + +#define LIMINE_SMBIOS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee } + +struct limine_smbios_response { + uint64_t revision; + LIMINE_PTR(void *) entry_32; + LIMINE_PTR(void *) entry_64; +}; + +struct limine_smbios_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smbios_response *) response; +}; + +/* EFI system table */ + +#define LIMINE_EFI_SYSTEM_TABLE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc } + +struct limine_efi_system_table_response { + uint64_t revision; + LIMINE_PTR(void *) address; +}; + +struct limine_efi_system_table_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_system_table_response *) response; +}; + +/* TPM event log */ + +#define LIMINE_TPM_EVENT_LOG_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x98e094fc7e76e979, 0xee8d8775c54e1d1f } + +#define LIMINE_TPM_EVENT_LOG_FORMAT_TCG_1_2 1 +#define LIMINE_TPM_EVENT_LOG_FORMAT_TCG_2 2 + +struct limine_tpm_event_log_response { + uint64_t revision; + uint64_t format; + uint64_t size; + LIMINE_PTR(void *) address; +}; + +struct limine_tpm_event_log_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_tpm_event_log_response *) response; +}; + +/* EFI memory map */ + +#define LIMINE_EFI_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 } + +struct limine_efi_memmap_response { + uint64_t revision; + LIMINE_PTR(void *) memmap; + uint64_t memmap_size; + uint64_t desc_size; + uint64_t desc_version; +}; + +struct limine_efi_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_memmap_response *) response; +}; + +/* Date at boot */ + +#define LIMINE_DATE_AT_BOOT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } + +struct limine_date_at_boot_response { + uint64_t revision; + int64_t timestamp; +}; + +struct limine_date_at_boot_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_date_at_boot_response *) response; +}; + +/* Executable address */ + +#define LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } + +struct limine_executable_address_response { + uint64_t revision; + uint64_t physical_base; + uint64_t virtual_base; +}; + +struct limine_executable_address_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_address_response *) response; +}; + +/* Device Tree Blob */ + +#define LIMINE_DTB_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 } + +struct limine_dtb_response { + uint64_t revision; + LIMINE_PTR(void *) dtb_ptr; +}; + +struct limine_dtb_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_dtb_response *) response; +}; + +/* RISC-V Boot Hart ID */ + +#define LIMINE_RISCV_BSP_HARTID_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 } + +struct limine_riscv_bsp_hartid_response { + uint64_t revision; + uint64_t bsp_hartid; +}; + +struct limine_riscv_bsp_hartid_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response; +}; + +/* Bootloader Performance */ + +#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 } + +struct limine_bootloader_performance_response { + uint64_t revision; + uint64_t reset_usec; + uint64_t init_usec; + uint64_t exec_usec; +}; + +struct limine_bootloader_performance_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_performance_response *) response; +}; + +#define LIMINE_X86_64_KEEP_IOMMU_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8ebaabe51f490179, 0x2aa86a59ffb4ab0f } + +struct limine_x86_64_keep_iommu_response { + uint64_t revision; +}; + +struct limine_x86_64_keep_iommu_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_x86_64_keep_iommu_response *) response; +}; + +/* TSC (Timestamp Counter) Frequency */ + +#define LIMINE_TSC_FREQUENCY_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x10f2ee1d87d195e4, 0xf747a2b78f6ddb31 } + +struct limine_tsc_frequency_response { + uint64_t revision; + uint64_t frequency; +}; + +struct limine_tsc_frequency_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_tsc_frequency_response *) response; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/vga_console.cpp b/src/kernel/vga_console.cpp deleted file mode 100644 index 51deabf..0000000 --- a/src/kernel/vga_console.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "vga_console.h" - -void vgaPrint(char* string) { - static unsigned short* vgaVideoMemory = (unsigned short*)0xb8000; - - for (unsigned int i = 0; string[i] != 0; i++) { - /* - The high byte in the VGA video memory contains colour info we don't want to overwrite. - So, we have to combine the high byte with the char we're writing. - */ - vgaVideoMemory[i] = (vgaVideoMemory[i] & 0xFF00) | string[i]; - } -} \ No newline at end of file diff --git a/src/kernel/vga_console.h b/src/kernel/vga_console.h deleted file mode 100644 index f46b390..0000000 --- a/src/kernel/vga_console.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void vgaPrint(char* string); \ No newline at end of file