From a048764a3df78e2e584d2a9223dc87bbd5a07063 Mon Sep 17 00:00:00 2001 From: AI Date: Mon, 23 Feb 2026 08:24:50 +0000 Subject: [PATCH] Setup simple kernel with Hello World output via debugcon (AI) --- CMakeLists.txt | 6 ++--- README.md | 2 +- output.txt | 1 + src/CMakeLists.txt | 1 + src/boot.S | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/kernel.c | 32 +++++++++++++++++++++-- 6 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 output.txt create mode 100644 src/boot.S diff --git a/CMakeLists.txt b/CMakeLists.txt index 19d2fa4..1fc9ab1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,9 @@ project(ClaudeOS C ASM) set(CMAKE_C_STANDARD 99) # We are building a kernel, so we don't want standard libraries -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffreestanding -m32 -g -O2 -Wall -Wextra") -set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32 -nostdlib") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffreestanding -m32 -fno-pie -fno-pic -fno-builtin -fno-stack-protector -g -O2 -Wall -Wextra") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32 -fno-pie -fno-pic") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32 -nostdlib -no-pie") # Define build output directory set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) diff --git a/README.md b/README.md index 5ce8e8c..e7aea3d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Once a task is completed, it should be checked off. - [x] Create directory structure - [x] Create initial build system -- [ ] Setup a simple kernel that writes `Hello, world` to Qemu debug port +- [x] Setup a simple kernel that writes `Hello, world` to Qemu debug port - [ ] Update the build system to create both ISO and Floppy images. Verify these work using a test script. The standard CMake build target should automatically generate both images. - [ ] Update the kernel to correctly setup the GDT - [ ] Create a physical memory allocator and mapper. The kernel should live in the upper last gigabyte of virtual memory. It should support different zones (e.g.: `SUB_16M`, `DEFAULT`, ...) These zones describe the region of memory that memory should be allocated in. If it is not possible to allocate in that region (because it is full, or has 0 capacity to begin with), it should fallback to another zone. diff --git a/output.txt b/output.txt new file mode 100644 index 0000000..a5c1966 --- /dev/null +++ b/output.txt @@ -0,0 +1 @@ +Hello, world diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe3e222..a61c842 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.16) add_executable(kernel + boot.S kernel.c ) diff --git a/src/boot.S b/src/boot.S new file mode 100644 index 0000000..bb02cd2 --- /dev/null +++ b/src/boot.S @@ -0,0 +1,65 @@ +#define ASM_FILE +#include + +/* Multiboot 1 header constants */ +.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 */ + +.section .multiboot +.align 4 +multiboot1_header: + .long MAGIC + .long FLAGS + .long CHECKSUM + +.align 8 +multiboot_header: + /* magic */ + .long MULTIBOOT2_HEADER_MAGIC + /* architecture: 0 (protected mode i386) */ + .long MULTIBOOT_ARCHITECTURE_I386 + /* header length */ + .long multiboot_header_end - multiboot_header + /* checksum */ + .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header)) + + /* Tags here */ + + /* End tag */ + .short MULTIBOOT_HEADER_TAG_END + .short 0 + .long 8 +multiboot_header_end: + +.section .bss +.align 16 +stack_bottom: +.skip 16384 # 16 KiB +stack_top: + +.section .text +.global _start +.type _start, @function +_start: + /* Set up stack */ + mov $stack_top, %esp + + /* Reset EFLAGS */ + push $0 + popf + + /* Push magic and multiboot info pointer onto stack for kernel_main */ + /* Multiboot2 puts magic in EAX, pointer in EBX */ + push %ebx + push %eax + + call kernel_main + + cli +1: hlt + jmp 1b + +.size _start, . - _start diff --git a/src/kernel.c b/src/kernel.c index 147888a..523dbc2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,3 +1,31 @@ -void _start() { - while(1) {} +#include +#include +#include + +static inline void outb(uint16_t port, uint8_t val) +{ + asm volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) ); +} + +void offset_print(const char *str) +{ + while (*str) { + outb(0xE9, *str); + str++; + } +} + +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +void kernel_main(uint32_t magic, uint32_t addr) { + (void)addr; // Unused for now + + if (magic != MULTIBOOT2_BOOTLOADER_MAGIC && magic != MULTIBOOT_BOOTLOADER_MAGIC) { + offset_print("Invalid magic number: "); + // I don't have hex print yet, but I can print something generic + offset_print("Unknown\n"); + return; + } + + offset_print("Hello, world\n"); }