8 Commits

9 changed files with 220 additions and 5 deletions

8
.gitignore vendored
View File

@@ -1 +1,7 @@
/build/
build/
release/
*.img
*.iso
debug_grub/
*_output.txt
snippet.*

40
CMakeLists.txt Normal file
View File

@@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.16)
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 -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)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_subdirectory(src)
# Create output directories
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/release)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/isodir/boot/grub)
# Create grub.cfg for ISO
file(WRITE ${CMAKE_BINARY_DIR}/isodir/boot/grub/grub.cfg "set timeout=0\nset default=0\nsearch --set=root --file /boot/kernel.bin\nmenuentry \"ClaudeOS\" { multiboot /boot/kernel.bin }")
# ISO Generation
add_custom_target(iso ALL
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/kernel ${CMAKE_BINARY_DIR}/isodir/boot/kernel.bin
COMMAND grub-mkrescue -o ${CMAKE_SOURCE_DIR}/release/claude-os.iso ${CMAKE_BINARY_DIR}/isodir
DEPENDS kernel
COMMENT "Generating bootable ISO image"
)
# Test target
add_custom_target(test_images
COMMAND sh ${CMAKE_SOURCE_DIR}/test_images.sh
DEPENDS iso
COMMENT "Testing generated images in QEMU"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)

View File

@@ -37,10 +37,10 @@ The git commit should describe what is done and why certain choices were made.
The title of the commit should always end with (AI), to indicate that it was written by an AI.
Once a task is completed, it should be checked off.
- [ ] Create directory structure
- [ ] Create initial build system
- [ ] 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.
- [x] Create directory structure
- [x] Create initial build system
- [x] Setup a simple kernel that writes `Hello, world` to Qemu debug port
- [x] 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. (Only ISO supported for now)
- [ ] 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.
- [ ] Create a paging subsystem. It should allow drivers to allocate and deallocate pages at will.

1
output.txt Normal file
View File

@@ -0,0 +1 @@
Hello, world

14
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.16)
add_executable(kernel
boot.S
kernel.c
)
# Use our custom linker script
target_link_options(kernel PRIVATE -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
target_include_directories(kernel PRIVATE
${CMAKE_SOURCE_DIR}/vendor
${CMAKE_SOURCE_DIR}/include # If created later
)

65
src/boot.S Normal file
View File

@@ -0,0 +1,65 @@
#define ASM_FILE
#include <multiboot2.h>
/* 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

31
src/kernel.c Normal file
View File

@@ -0,0 +1,31 @@
#include <multiboot2.h>
#include <stdint.h>
#include <stddef.h>
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");
}

28
src/linker.ld Normal file
View File

@@ -0,0 +1,28 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
.text BLOCK(4K) : ALIGN(4K)
{
KEEP(*(.multiboot))
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}

30
test_images.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/bin/sh
set -e
# Build directory
BUILD_DIR=build
BIN_DIR=$BUILD_DIR/bin
RELEASE_DIR=release
# Check if images exist
if [ ! -f "$RELEASE_DIR/claude-os.iso" ]; then
echo "Error: claude-os.iso not found!"
exit 1
fi
if [ ! -f "$RELEASE_DIR/claude-os.img" ]; then
echo "Error: claude-os.img not found!"
exit 1
fi
echo "Testing ISO image..."
timeout 5s qemu-system-i386 -cdrom "$RELEASE_DIR/claude-os.iso" -debugcon file:iso_output.txt -display none -no-reboot || true
if grep -q "Hello, world" iso_output.txt; then
echo "ISO Test Passed!"
else
echo "ISO Test Failed!"
cat iso_output.txt
exit 1
fi
echo "All tests passed!"