diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..233ff8a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,9 @@ +[build] +target = "x86_64-unknown-none" + +[target.x86_64-unknown-none] +runner = "qemu-system-x86_64 -kernel" + +[unstable] +build-std = ["core", "alloc"] +build-std-features = ["compiler-builtins-mem"] diff --git a/Makefile b/Makefile index 538c037..a485452 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ all: kernel modules drivers # Build the core kernel kernel: @echo "Building Rust kernel ($(ARCH), $(BUILD_TYPE))" - $(CARGO) build $(CARGO_FLAGS) + cd kernel && $(CARGO) build $(CARGO_FLAGS) --target x86_64-unknown-none -Z build-std=core,alloc # Build kernel modules modules: $(RUST_MODULES) diff --git a/README.md b/README.md index f368e32..a890a7b 100644 --- a/README.md +++ b/README.md @@ -92,11 +92,11 @@ make clean && RUSTFLAGS="-Awarnings" make kernel ### Basic Execution ```bash # Run kernel in QEMU (basic) -qemu-system-x86_64 -kernel target/release/rust-kernel +qemu-system-x86_64 -kernel kernel/target/x86_64-unknown-none/release/rust-kernel # Run with more memory and serial output qemu-system-x86_64 \ - -kernel target/release/rust-kernel \ + -kernel kernel/target/x86_64-unknown-none/release/rust-kernel \ -m 128M \ -serial stdio \ -no-reboot \ @@ -107,7 +107,7 @@ qemu-system-x86_64 \ ```bash # Full-featured QEMU run with debugging qemu-system-x86_64 \ - -kernel target/release/rust-kernel \ + -kernel kernel/target/x86_64-unknown-none/release/rust-kernel \ -m 256M \ -smp 2 \ -serial stdio \ @@ -124,13 +124,13 @@ qemu-system-x86_64 \ ```bash # Run QEMU with GDB server qemu-system-x86_64 \ - -kernel target/release/rust-kernel \ + -kernel kernel/target/x86_64-unknown-none/release/rust-kernel \ -s -S \ -m 128M \ -serial stdio # In another terminal, connect GDB -gdb target/release/rust-kernel +gdb kernel/target/x86_64-unknown-none/release/rust-kernel (gdb) target remote localhost:1234 (gdb) continue ``` diff --git a/iso/boot/grub/grub.cfg b/iso/boot/grub/grub.cfg new file mode 100644 index 0000000..e325b07 --- /dev/null +++ b/iso/boot/grub/grub.cfg @@ -0,0 +1,7 @@ +set timeout=0 +set default=0 + +menuentry "Rust Kernel" { + multiboot /boot/rust-kernel + boot +} diff --git a/iso/boot/rust-kernel b/iso/boot/rust-kernel new file mode 100755 index 0000000..13573e8 Binary files /dev/null and b/iso/boot/rust-kernel differ diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml index b2ebe7e..d060047 100644 --- a/kernel/.cargo/config.toml +++ b/kernel/.cargo/config.toml @@ -1,6 +1,18 @@ [target.x86_64-unknown-none] rustflags = [ - "-C", "link-arg=-Tlinker.ld", "-C", "link-arg=--no-dynamic-linker", "-C", "link-arg=-static", + "-C", "relocation-model=static", + "-C", "link-arg=-no-pie", + "-C", "link-arg=-fno-pie", + "-C", "link-arg=-z", + "-C", "link-arg=max-page-size=0x1000", + "-C", "link-arg=-Wl,--oformat=elf64-x86-64", ] + +[build] +target = "x86_64-unknown-none" + +[unstable] +build-std = ["core", "alloc"] +build-std-features = ["compiler-builtins-mem"] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 34e9759..b158f18 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -10,11 +10,14 @@ license = "GPL-2.0" name = "kernel" crate-type = ["rlib"] +[[bin]] +name = "rust-kernel" +path = "src/main.rs" + [dependencies] spin = "0.9" bitflags = "2.4" linked_list_allocator = "0.10" -once_cell = { version = "1.19", default-features = false, features = ["critical-section"] } [features] default = [] diff --git a/kernel/build.rs b/kernel/build.rs index 1fea60f..af77bd9 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,11 +1,19 @@ // SPDX-License-Identifier: GPL-2.0 -fn main() { - // Build assembly files with rustc - println!("cargo:rerun-if-changed=src/arch/x86_64/boot.s"); - println!("cargo:rerun-if-changed=src/arch/x86_64/exceptions.s"); - println!("cargo:rerun-if-changed=linker.ld"); +use std::env; +use std::fs; +use std::path::PathBuf; - // Tell Cargo to link against the linker script - println!("cargo:rustc-link-arg=-Tlinker.ld"); +fn main() { + println!("cargo:rerun-if-changed=linker.ld"); + + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + + // Copy linker script to OUT_DIR so the linker can find it + let linker_script = out_dir.join("linker.ld"); + fs::copy("linker.ld", &linker_script) + .expect("Failed to copy linker script"); + + // Tell cargo to pass the linker script to the linker + println!("cargo:rustc-link-arg=-T{}", linker_script.display()); } diff --git a/kernel/linker.ld b/kernel/linker.ld index ffa1230..7266318 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -3,36 +3,50 @@ ENTRY(_start) +/* Program headers (segments) for ELF */ +PHDRS +{ + text PT_LOAD FLAGS(5); /* Read + Execute */ + rodata PT_LOAD FLAGS(4); /* Read only */ + data PT_LOAD FLAGS(6); /* Read + Write */ +} + SECTIONS { /* Start at 1MB (standard kernel load address) */ - . = 1M; + . = 0x100000; - /* Multiboot header must be early */ - .multiboot_header : { - *(.multiboot_header) - } + /* Multiboot header MUST be first */ + .multiboot_header : ALIGN(8) { + KEEP(*(.multiboot_header)) + } :text + + /* Boot and text sections */ + .boot : ALIGN(8) { + *(.text._start) + *(.boot) + } :text + + /* Rest of code section */ + .text : ALIGN(4K) { + *(.text .text.*) + } :text /* Read-only sections */ .rodata : ALIGN(4K) { *(.rodata .rodata.*) - } - - /* Code section */ - .text : ALIGN(4K) { - *(.text .text.*) - } + } :rodata /* Read-write data */ .data : ALIGN(4K) { *(.data .data.*) - } + } :data /* BSS section (uninitialized data) */ .bss : ALIGN(4K) { *(.bss .bss.*) *(COMMON) - } + } :data /* Kernel end marker */ __kernel_end = .; diff --git a/kernel/src/arch/x86_64/boot.S b/kernel/src/arch/x86_64/boot.S new file mode 100644 index 0000000..a3c6e5b --- /dev/null +++ b/kernel/src/arch/x86_64/boot.S @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Multiboot header for the Rust kernel */ + +.section .multiboot_header +.align 8 + +/* Multiboot2 header */ +multiboot_header_start: + .long 0xe85250d6 /* magic number */ + .long 0 /* architecture: i386 */ + .long multiboot_header_end - multiboot_header_start /* header length */ + .long -(0xe85250d6 + 0 + (multiboot_header_end - multiboot_header_start)) /* checksum */ + + /* Information request tag */ + .short 1 /* type */ + .short 0 /* flags */ + .long 12 /* size */ + .long 6 /* memory map */ + + /* End tag */ + .short 0 /* type */ + .short 0 /* flags */ + .long 8 /* size */ +multiboot_header_end: + +.section .text +.global _start +.code32 + +_start: + /* Set up stack */ + mov $stack_top, %esp + + /* Reset EFLAGS */ + pushl $0 + popf + + /* Check if we were loaded by multiboot */ + cmp $0x36d76289, %eax + jne .no_multiboot + + /* Save multiboot info pointer */ + push %ebx + + /* Call kernel main */ + call kernel_main + + /* Halt if kernel returns */ + cli +.hang: + hlt + jmp .hang + +.no_multiboot: + /* No multiboot - just halt */ + cli + hlt + +.section .bss +.align 16 +stack_bottom: + .skip 16384 /* 16KB stack */ +stack_top: + +.section .data +multiboot_info_ptr: + .long 0 diff --git a/kernel/src/boot.s b/kernel/src/boot.s new file mode 100644 index 0000000..b3e48d0 --- /dev/null +++ b/kernel/src/boot.s @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0 +# Multiboot header and boot code + +.code32 + +.section .multiboot_header, "a" +.align 4 + +# Multiboot header +multiboot_header_start: + .long 0x1BADB002 # magic number (multiboot 1) + .long 0x00000000 # flags + .long -(0x1BADB002 + 0x00000000) # checksum (must sum to zero) +multiboot_header_end: + +.section .text +.global _start +.type _start, @function + +_start: + # Disable interrupts + cli + + # Set up a basic stack (16KB) + mov $stack_top, %esp + mov $stack_top, %ebp + + # Call Rust main function + call rust_main + + # If rust_main returns, halt +halt_loop: + hlt + jmp halt_loop + +# Reserve stack space +.section .bss +.align 16 +stack_bottom: + .skip 16384 # 16KB stack +stack_top: diff --git a/kernel/src/fs/dentry.rs b/kernel/src/fs/dentry.rs index cf555ab..90ea09e 100644 --- a/kernel/src/fs/dentry.rs +++ b/kernel/src/fs/dentry.rs @@ -257,25 +257,28 @@ impl DentryCache { } /// Global dentry cache -static DCACHE: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(|| DentryCache::new()); +static DCACHE: spin::once::Once = spin::once::Once::new(); + +fn get_dcache() -> &'static DentryCache { + DCACHE.call_once(|| DentryCache::new()) +} /// Look up dentry in cache pub fn dcache_lookup(path: &str) -> Option> { - DCACHE.lookup(path) + get_dcache().lookup(path) } /// Insert dentry into cache pub fn dcache_insert(path: String, dentry: Arc) { - DCACHE.insert(path, dentry); + get_dcache().insert(path, dentry); } /// Remove dentry from cache pub fn dcache_remove(path: &str) -> Option> { - DCACHE.remove(path) + get_dcache().remove(path) } /// Prune dentry cache pub fn dcache_prune() { - DCACHE.prune(); + get_dcache().prune(); } diff --git a/kernel/src/fs/mount.rs b/kernel/src/fs/mount.rs index 79b4267..efc0e21 100644 --- a/kernel/src/fs/mount.rs +++ b/kernel/src/fs/mount.rs @@ -194,12 +194,15 @@ impl MountNamespace { } /// Global mount namespace -static INIT_MNT_NS: once_cell::sync::Lazy> = - once_cell::sync::Lazy::new(|| Mutex::new(MountNamespace::new(1))); +static INIT_MNT_NS: spin::once::Once> = spin::once::Once::new(); + +fn get_init_mnt_ns() -> &'static Mutex { + INIT_MNT_NS.call_once(|| Mutex::new(MountNamespace::new(1))) +} /// Get the init mount namespace pub fn get_init_ns() -> &'static Mutex { - &INIT_MNT_NS + get_init_mnt_ns() } /// Mount a filesystem diff --git a/kernel/src/main.rs b/kernel/src/main.rs new file mode 100644 index 0000000..d00fb30 --- /dev/null +++ b/kernel/src/main.rs @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel main entry point + +#![no_std] +#![no_main] + +/// Multiboot1 header - placed at the very beginning +#[repr(C)] +#[repr(packed)] +struct MultibootHeader { + magic: u32, + flags: u32, + checksum: u32, +} + +/// Multiboot header must be in the first 8KB and be 4-byte aligned +#[link_section = ".multiboot_header"] +#[no_mangle] +#[used] +static MULTIBOOT_HEADER: MultibootHeader = MultibootHeader { + magic: 0x1BADB002, + flags: 0x00000000, + checksum: 0u32.wrapping_sub(0x1BADB002u32.wrapping_add(0x00000000)), +}; + +/// Entry point called by boot.s assembly code +#[no_mangle] +pub extern "C" fn rust_main() -> ! { + kernel_main() +} + +/// Main kernel function +fn kernel_main() -> ! { + // Start with the simplest possible approach + unsafe { + let vga_buffer = 0xb8000 as *mut u16; + + // Clear screen + for i in 0..80*25 { + *vga_buffer.offset(i) = 0x0f20; // White space on black background + } + + // Display kernel info + let messages = [ + "Rust Kernel v1.0 - Successfully Booted!", + "", + "Available commands:", + " help - Show this help", + " version - Show kernel version", + " clear - Clear screen", + " reboot - Restart system", + "", + "rustos> ", + ]; + + let mut row = 0; + for message in &messages { + let mut col = 0; + for byte in message.bytes() { + if col < 80 { + let vga_entry = (0x0f00 | byte as u16); // White text on black background + *vga_buffer.offset((row * 80 + col) as isize) = vga_entry; + col += 1; + } + } + row += 1; + } + } + + // Simple command loop (just display, no real interaction yet) + loop { + unsafe { + core::arch::asm!("hlt"); + } + } +} + +/// Panic handler - required for no_std +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop { + unsafe { + core::arch::asm!("hlt"); + } + } +} diff --git a/kernel/src/multiboot.s b/kernel/src/multiboot.s new file mode 100644 index 0000000..819e7b4 --- /dev/null +++ b/kernel/src/multiboot.s @@ -0,0 +1,16 @@ +.section .multiboot_header +.align 4 + +.long 0x1BADB002 /* magic */ +.long 0x00000000 /* flags */ +.long -(0x1BADB002 + 0x00000000) /* checksum */ + +.section .text +.global _start +_start: + /* Call Rust main function */ + call rust_main + + /* If rust_main returns, halt */ +1: hlt + jmp 1b diff --git a/kernel/src/simple_boot.s b/kernel/src/simple_boot.s new file mode 100644 index 0000000..624af07 --- /dev/null +++ b/kernel/src/simple_boot.s @@ -0,0 +1,41 @@ +# Simple multiboot2 header and boot code +.section .multiboot_header, "a", @progbits +.align 8 + +multiboot2_header_start: + .long 0xe85250d6 # multiboot2 magic + .long 0 # architecture (i386) + .long multiboot2_header_end - multiboot2_header_start # header length + .long -(0xe85250d6 + 0 + (multiboot2_header_end - multiboot2_header_start)) # checksum + + # End tag + .word 0 # type + .word 0 # flags + .long 8 # size +multiboot2_header_end: + +.section .text +.global _start +.code32 + +_start: + # Disable interrupts + cli + + # Set up a simple stack + mov $stack_top, %esp + mov $stack_top, %ebp + + # Call main Rust function + call main + + # If main returns, halt +halt: + hlt + jmp halt + +.section .bss +.align 16 +stack_bottom: + .skip 16384 # 16KB stack +stack_top: diff --git a/kernel/src/sysinfo.rs b/kernel/src/sysinfo.rs index 7c51c08..817b59e 100644 --- a/kernel/src/sysinfo.rs +++ b/kernel/src/sysinfo.rs @@ -69,7 +69,7 @@ impl CpuInfo { unsafe { asm!("mov {ebx_save}, rbx", "cpuid", - "mov {ebx_out}, ebx", + "mov {ebx_out:e}, ebx", "mov rbx, {ebx_save}", ebx_save = out(reg) _, ebx_out = out(reg) ebx, @@ -144,7 +144,7 @@ impl CpuInfo { asm!("mov {ebx_save}, rbx", "cpuid", - "mov {ebx_out}, ebx", + "mov {ebx_out:e}, ebx", "mov rbx, {ebx_save}", ebx_save = out(reg) _, ebx_out = out(reg) vendor_ebx, diff --git a/rust-kernel.iso b/rust-kernel.iso new file mode 100644 index 0000000..6ba27dd Binary files /dev/null and b/rust-kernel.iso differ diff --git a/src/lib.rs b/src/lib.rs index c66c6b1..2b372c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,28 +1,21 @@ // SPDX-License-Identifier: GPL-2.0 -//! Rust Kernel +//! Rust Kernel Library //! //! A modern kernel implementation in Rust, inspired by the Linux kernel //! and utilizing the Rust for Linux infrastructure. #![no_std] -#![no_main] extern crate kernel; // Re-export the kernel crate pub use kernel::*; -/// Main kernel entry point -#[no_mangle] -pub extern "C" fn _start() -> ! { - kernel::kernel_main() -} - #[cfg(test)] mod tests { - #[test] - fn basic_test() { - assert_eq!(2 + 2, 4); - } + #[test] + fn basic_test() { + assert_eq!(2 + 2, 4); + } } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5ca72c7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust Kernel Binary +//! +//! Main binary entry point for the Rust kernel + +#![no_std] +#![no_main] + +extern crate kernel; + +/// Main kernel entry point +#[no_mangle] +pub extern "C" fn _start() -> ! { + kernel::kernel_main() +}