From ac4cf9a27bfc2dfe551871fa62011f75569538a6 Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Sat, 16 Nov 2024 15:13:05 +0000 Subject: [PATCH] initial commit -- framebuffer Hello, World! --- .cargo/config.toml | 13 +++ .gitignore | 52 ++++++++++ .vscode/settings.json | 20 ++++ Cargo.toml | 29 ++++++ bacon.toml | 108 ++++++++++++++++++++ config/limine.conf | 10 ++ kernel/Cargo.toml | 16 +++ kernel/build.rs | 38 ++++++++ kernel/linker.ld | 70 +++++++++++++ kernel/src/font.rs | 200 ++++++++++++++++++++++++++++++++++++++ kernel/src/main.rs | 40 ++++++++ kernel/src/render.rs | 118 ++++++++++++++++++++++ kernel/src/sys/mod.rs | 2 + kernel/x86_64-kernel.json | 29 ++++++ rust-toolchain.toml | 4 + scripts/run.sh | 114 ++++++++++++++++++++++ 16 files changed, 863 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Cargo.toml create mode 100644 bacon.toml create mode 100644 config/limine.conf create mode 100644 kernel/Cargo.toml create mode 100644 kernel/build.rs create mode 100644 kernel/linker.ld create mode 100644 kernel/src/font.rs create mode 100644 kernel/src/main.rs create mode 100644 kernel/src/render.rs create mode 100644 kernel/src/sys/mod.rs create mode 100644 kernel/x86_64-kernel.json create mode 100644 rust-toolchain.toml create mode 100755 scripts/run.sh diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..c891815 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,13 @@ +[build] +target = "x86_64-kernel" +target-dir = "build/target" + +[unstable] +build-std = ["core", "compiler_builtins", "alloc"] +build-std-features = ["compiler-builtins-mem"] + +[env] +RUST_TARGET_PATH = { value = "kernel", relative = true } + +[target.x86_64-kernel] +runner = "scripts/run.sh" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db39409 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# Build output directories +/build/ +/target/ +**/*.rs.bk + +# Generated files +*.o +*.bin +*.iso +*.img +*.elf +*.efi +*.log +qemu.log + +# Rust specific +Cargo.lock + +# Editor/IDE specific +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +.idea/ +*.swp +*.swo +*~ + +# OS specific +.DS_Store +.directory +.Trash-* +Thumbs.db + +# Debug files +*.pdb +*.sym + +# Bootloader files +/build/limine/ +**/limine-bios* +**/limine-uefi* +**/BOOT*.EFI + +# Environment +.env +.env.local +.envrc + +# Backup files +*.bak +*.backup +*.tmp \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0610628 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "rust-analyzer.check.allTargets": false, + "rust-analyzer.check.extraArgs": [ + "--target", + "x86_64-kernel" + ], + "rust-analyzer.cargo.target": "x86_64-kernel", + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.checkOnSave.extraArgs": [ + "--target", + "x86_64-kernel" + ], + "rust-analyzer.cargo.features": [], + "rust-analyzer.procMacro.enable": true, + "rust-analyzer.cargo.buildScripts.enable": true, + "rust-analyzer.cargo.buildScripts.overrideCommand": null, + "rust-analyzer.server.extraEnv": { + "RUST_TARGET_PATH": "${workspaceFolder}/kernel" + } +} diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3aca2dd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,29 @@ +[workspace] +members = [ + "kernel" +] +resolver = "2" + +[profile.dev] +panic = "abort" +opt-level = "z" +debug = true +debug-assertions = true +overflow-checks = true +lto = false +incremental = false +codegen-units = 1 + +[profile.release] +panic = "abort" +opt-level = "z" +debug = false +debug-assertions = false +overflow-checks = false +lto = true +incremental = false +codegen-units = 1 + +[workspace.package] +version = "0.1.0" +edition = "2021" diff --git a/bacon.toml b/bacon.toml new file mode 100644 index 0000000..62488ea --- /dev/null +++ b/bacon.toml @@ -0,0 +1,108 @@ +# This is a configuration file for the bacon tool +# +# Bacon repository: https://github.com/Canop/bacon +# Complete help on configuration: https://dystroy.org/bacon/config/ +# You can also check bacon's own bacon.toml file +# as an example: https://github.com/Canop/bacon/blob/main/bacon.toml + +default_job = "check" + +[jobs.check] +command = ["cargo", "check", "--color", "always"] +need_stdout = false + +[jobs.check-all] +command = ["cargo", "check", "--all-targets", "--color", "always"] +need_stdout = false + +# Run clippy on the default target +[jobs.clippy] +command = [ + "cargo", "clippy", + "--color", "always", +] +need_stdout = false + +# Run clippy on all targets +# To disable some lints, you may change the job this way: +# [jobs.clippy-all] +# command = [ +# "cargo", "clippy", +# "--all-targets", +# "--color", "always", +# "--", +# "-A", "clippy::bool_to_int_with_if", +# "-A", "clippy::collapsible_if", +# "-A", "clippy::derive_partial_eq_without_eq", +# ] +# need_stdout = false +[jobs.clippy-all] +command = [ + "cargo", "clippy", + "--all-targets", + "--color", "always", +] +need_stdout = false + +# This job lets you run +# - all tests: bacon test +# - a specific test: bacon test -- config::test_default_files +# - the tests of a package: bacon test -- -- -p config +[jobs.test] +command = [ + "cargo", "test", "--color", "always", + "--", "--color", "always", # see https://github.com/Canop/bacon/issues/124 +] +need_stdout = true + +[jobs.nextest] +command = ["cargo", "nextest", "run", "--color", "always", "--hide-progress-bar", "--failure-output", "final"] +need_stdout = true +analyzer = "nextest" + +[jobs.doc] +command = ["cargo", "doc", "--color", "always", "--no-deps"] +need_stdout = false + +# If the doc compiles, then it opens in your browser and bacon switches +# to the previous job +[jobs.doc-open] +command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] +need_stdout = false +on_success = "back" # so that we don't open the browser at each change + +# You can run your application and have the result displayed in bacon, +# *if* it makes sense for this crate. +# Don't forget the `--color always` part or the errors won't be +# properly parsed. +# If your program never stops (eg a server), you may set `background` +# to false to have the cargo run output immediately displayed instead +# of waiting for program's end. If you prefer to have it restarted at +# every change, then uncomment the 'on_change_strategy' line. +[jobs.run] +command = [ + "cargo", "run", + "--color", "always", + # put launch parameters for your program behind a `--` separator +] +need_stdout = true +allow_warnings = true +background = true +on_change_strategy = "kill_then_restart" + +# This parameterized job runs the example of your choice, as soon +# as the code compiles. +# Call it as +# bacon ex -- my-example +[jobs.ex] +command = ["cargo", "run", "--color", "always", "--example"] +need_stdout = true +allow_warnings = true + +# You may define here keybindings that would be specific to +# a project, for example a shortcut to launch a specific job. +# Shortcuts to internal functions (scrolling, toggling, etc.) +# should go in your personal global prefs.toml file instead. +[keybindings] +# alt-m = "job:my-job" +c = "job:clippy-all" # comment this to have 'c' run clippy on only the default target diff --git a/config/limine.conf b/config/limine.conf new file mode 100644 index 0000000..0ffe391 --- /dev/null +++ b/config/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. +/GoofyAhhOS + # We use the Limine boot protocol. + protocol: limine + + # Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located. + kernel_path: boot():/boot/kernel \ No newline at end of file diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml new file mode 100644 index 0000000..f5bd835 --- /dev/null +++ b/kernel/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "kernel" +version.workspace = true +edition.workspace = true + +[dependencies] +limine = "0.3.1" +spin = "0.9.8" +bitflags = "2.4.0" +lazy_static = { version = "1.5.0", features = ["spin", "spin_no_std"] } + +[[bin]] +name = "kernel" +path = "src/main.rs" +test = false +bench = false diff --git a/kernel/build.rs b/kernel/build.rs new file mode 100644 index 0000000..7d40db1 --- /dev/null +++ b/kernel/build.rs @@ -0,0 +1,38 @@ +use std::process::Command; +use std::{env, path::Path}; + +fn main() { + // Get the output directory from cargo + let out_dir = env::var("OUT_DIR").unwrap(); + let build_dir = Path::new(&out_dir).ancestors().nth(3).unwrap(); + let iso_root = build_dir.join("iso_root"); + + // Create ISO directory structure + std::fs::create_dir_all(iso_root.join("boot/limine")).unwrap(); + std::fs::create_dir_all(iso_root.join("EFI/BOOT")).unwrap(); + + // Clone and build Limine if needed + let limine_dir = build_dir.join("limine"); + if !limine_dir.exists() { + Command::new("git") + .args([ + "clone", + "https://github.com/limine-bootloader/limine.git", + "--branch=v8.x-binary", + "--depth=1", + ]) + .arg(&limine_dir) + .status() + .expect("Failed to clone Limine"); + + Command::new("make") + .current_dir(&limine_dir) + .status() + .expect("Failed to build Limine"); + } + + // Tell cargo to rerun if these files change + println!("cargo:rerun-if-changed=src"); + println!("cargo:rerun-if-changed=linker.ld"); + println!("cargo:rerun-if-changed=../config/limine.conf"); +} diff --git a/kernel/linker.ld b/kernel/linker.ld new file mode 100644 index 0000000..b327207 --- /dev/null +++ b/kernel/linker.ld @@ -0,0 +1,70 @@ +/* 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 + + /* 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/kernel/src/font.rs b/kernel/src/font.rs new file mode 100644 index 0000000..0cd6ba4 --- /dev/null +++ b/kernel/src/font.rs @@ -0,0 +1,200 @@ +pub static FONT: [u8; 128 * 16] = [ + // ASCII 0-31 (Control Characters) - Using simple box patterns + // NUL (0) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // SOH (1) + 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // STX (2) + 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // ETX (3) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // EOT (4) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // ENQ (5) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // ACK (6) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // BEL (7) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + // BS (8) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, + // HT (9) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, + // LF (10) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, + // VT (11) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, + // FF (12) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, + // CR (13) + 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, + // SO (14) + 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // SI (15) + 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // DLE (16) + 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // DC1 (17) + 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // DC2 (18) + 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // DC3 (19) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // DC4 (20) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // NAK (21) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // SYN (22) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // ETB (23) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, + // CAN (24) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, 0xFF, + // EM (25) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, 0xFF, + // SUB (26) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0xFF, + // ESC (27) + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, + // FS (28) + 0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, + // GS (29) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, + // RS (30) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0x18, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // US (31) + 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + // Space (32) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // ! (33) + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + // " (34) + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // # (35) + 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, + // $ (36) + 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00, + // % (37) + 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, + // & (38) + 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, + // ' (39) + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // ( (40) + 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + // ) (41) + 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + // * (42) + 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // + (43) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // , (44) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + // - (45) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // . (46) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + // / (47) + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, + // 0-9 (48-57) + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00, + // : (58) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + // ; (59) + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + // < (60) + 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + // = (61) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // > (62) + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + // ? (63) + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + // @ (64) + 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, + // A-Z (65-90) + 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + // [ (91) + 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, + // \ (92) + 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + // ] (93) + 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00, + // ^ (94) + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // _ (95) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + // ` (96) + 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // a-z (97-122) - lowercase letters + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, + // { (123) + 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, + // | (124) + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + // } (125) + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + // ~ (126) + 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // DEL (127) + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, +]; \ No newline at end of file diff --git a/kernel/src/main.rs b/kernel/src/main.rs new file mode 100644 index 0000000..472805c --- /dev/null +++ b/kernel/src/main.rs @@ -0,0 +1,40 @@ +#![no_std] // Don't link the Rust standard library +#![no_main] // Disable all Rust-level entry points + +use core::panic::PanicInfo; +use limine::*; + +use limine::request::{ + FramebufferRequest, RequestsEndMarker, RequestsStartMarker, +}; + +mod font; +mod render; + +use crate::font::FONT; + +// Set the base revision +static BASE_REVISION: BaseRevision = BaseRevision::new(); + + +// Halt and catch fire function +fn hcf() -> ! { + loop { + unsafe { core::arch::asm!("cli; hlt") } + } +} + +// Called on panic +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + hcf() +} + +// Kernel entry point +#[no_mangle] +pub extern "C" fn kmain() -> ! { + render::init(); + render::write_string("Welcome to GoofyAhhOS!\nthis is the superior os\nif you disagree you are a heretic in the name of steven.", 0xff0000, 0); + + hcf() +} diff --git a/kernel/src/render.rs b/kernel/src/render.rs new file mode 100644 index 0000000..64bc8e7 --- /dev/null +++ b/kernel/src/render.rs @@ -0,0 +1,118 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use lazy_static::lazy_static; +use limine::framebuffer::Framebuffer; +use spin::Mutex; +use limine::request::FramebufferRequest; + +use crate::font::FONT; + +pub struct FramebufferWriter<'a> { + framebuffer: Framebuffer<'a>, + x_pos: AtomicUsize, + y_pos: AtomicUsize, +} + +unsafe impl<'a> Send for FramebufferWriter<'a> {} +unsafe impl<'a> Sync for FramebufferWriter<'a> {} + +impl<'a> FramebufferWriter<'a> { + pub fn new(framebuffer: Framebuffer<'a>) -> Self { + Self { + framebuffer, + x_pos: AtomicUsize::new(0), + y_pos: AtomicUsize::new(0), + } + } + + pub fn write_pixel(&self, x: usize, y: usize, color: u32) { + let pitch = self.framebuffer.pitch() as usize; + let bpp = (self.framebuffer.bpp() / 8) as usize; + let pixel_offset = y * pitch + x * bpp; + + unsafe { + *(self.framebuffer.addr().add(pixel_offset) as *mut u32) = color; + } + } + + pub fn write_char(&self, x: u32, y: u32, fg_color: u32, bg_color: u32, mut c: u8) { + if c < 32 || c > 126 { + c = '?' as u8; + } + + let data: &[u8] = &FONT[c as usize * 16..(c as usize + 1) * 16]; + + for row in 0..16 { + let line: u8 = data[row]; + for col in 0..8 { + let pixel_x: u32 = x + col; + let pixel_y: u32 = y + row as u32; + if line & (0x80 >> col) != 0 { + self.write_pixel(pixel_x as usize, pixel_y as usize, fg_color); + } else { + self.write_pixel(pixel_x as usize, pixel_y as usize, bg_color); + } + } + } + } + + pub fn write_string(&self, x: u32, y: u32, fg_color: u32, bg_color: u32, s: &str) { + let mut curr_x: u32 = x; + let mut curr_y: u32 = y; + + for c in s.chars() { + if c == '\n' { + curr_x = x; + curr_y += 16; + continue; + } + + if curr_x + 8 > self.framebuffer.width() as u32 { + curr_x = x; + curr_y += 16; + } + + if curr_y + 16 > self.framebuffer.height() as u32 { + break; + } + + self.write_char(curr_x, curr_y, fg_color, bg_color, c as u8); + curr_x += 8; + } + } + + pub fn clear(&self, color: u32) { + let width = self.framebuffer.width() as usize; + let height = self.framebuffer.height() as usize; + + for y in 0..height { + for x in 0..width { + self.write_pixel(x, y, color); + } + } + } +} + +static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + +lazy_static! { + pub static ref FRAMEBUFFER_WRITER: Mutex>> = Mutex::new(None); +} + +pub fn init() { + if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { + // The framebuffer from the response has a 'static lifetime + let framebuffer = framebuffer_response.framebuffers().next().unwrap(); + *FRAMEBUFFER_WRITER.lock() = Some(FramebufferWriter::new(framebuffer)); + clear_screen(0x00000000); + } +} + +pub fn clear_screen(color: u32) { + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_ref() { + writer.clear(color); + } +} + +pub fn write_string(s: &str, fg_color: u32, bg_color: u32) { + FRAMEBUFFER_WRITER.lock().as_ref().unwrap().write_string(0, 0, fg_color, bg_color, s); +} diff --git a/kernel/src/sys/mod.rs b/kernel/src/sys/mod.rs new file mode 100644 index 0000000..9daa70f --- /dev/null +++ b/kernel/src/sys/mod.rs @@ -0,0 +1,2 @@ +pub mod std; +mod kernel; \ No newline at end of file diff --git a/kernel/x86_64-kernel.json b/kernel/x86_64-kernel.json new file mode 100644 index 0000000..76085cc --- /dev/null +++ b/kernel/x86_64-kernel.json @@ -0,0 +1,29 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float", + "relocation-model": "static", + "code-model": "kernel", + "pre-link-args": { + "ld.lld": [ + "--script=/home/fantasypvp/Projects/OSDev/GoofyAhhOS/kernel/linker.ld", + "-nostdlib", + "--no-dynamic-linker", + "-static", + "--no-pie", + "--gc-sections", + "--build-id=none", + "-z", "max-page-size=0x1000" + ] + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..6484771 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly" +components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] +targets = ["x86_64-unknown-none"] diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..2ac5373 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Error handling +set -e +trap 'echo -e "${RED}${BOLD}error${NC}: build failed" >&2' ERR + +# Logging functions +info() { + echo -e "${BLUE}${BOLD}info${NC}: $1" +} + +compiling() { + echo -e "${GREEN}${BOLD}Compiling${NC} $1" +} + +warning() { + echo -e "${YELLOW}${BOLD}warning${NC}: $1" >&2 +} + +error() { + echo -e "${RED}${BOLD}error${NC}: $1" >&2 + exit 1 +} + +build_dir=build +iso_root=$build_dir/iso_root +kernel_path=$1 +kernel_name=$(basename $kernel_path) + +# Check for required tools +check_tools() { + local missing=0 + for tool in xorriso git qemu-system-x86_64; do + if ! command -v $tool >/dev/null 2>&1; then + error "required tool '$tool' is not installed" + missing=1 + fi + done + if [ $missing -eq 1 ]; then + error "missing required tools" + fi +} + +# Create build directory structure +info "Creating build directory structure" +mkdir -p "$iso_root/boot/limine" +mkdir -p "$iso_root/EFI/BOOT" + +# Clone Limine if needed +if [ ! -d "$build_dir/limine" ]; then + compiling "limine bootloader" + git clone https://github.com/limine-bootloader/limine.git --branch=v8.x-binary --depth=1 "$build_dir/limine" || error "failed to clone limine" + make -C "$build_dir/limine" || error "failed to build limine" +fi + +# Copy files +info "Copying files to ISO root" +cp -v "$kernel_path" "$iso_root/boot/kernel" || error "failed to copy kernel" +cp -v config/limine.conf "$iso_root/boot/limine/" || error "failed to copy limine config" +cp -v "$build_dir/limine/limine-bios.sys" "$build_dir/limine/limine-bios-cd.bin" \ + "$build_dir/limine/limine-uefi-cd.bin" "$iso_root/boot/limine/" || error "failed to copy limine files" +cp -v "$build_dir/limine/BOOTX64.EFI" "$iso_root/EFI/BOOT/" || error "failed to copy BOOTX64.EFI" +cp -v "$build_dir/limine/BOOTIA32.EFI" "$iso_root/EFI/BOOT/" || error "failed to copy BOOTIA32.EFI" + +# Create ISO +compiling "bootable ISO image" +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 "$build_dir/image.iso" || error "failed to create ISO" + +# Install Limine +info "Installing Limine bootloader" +"$build_dir/limine/limine" bios-install "$build_dir/image.iso" || error "failed to install limine" + +# Check if KVM is available +if [ "${KVM_FLAG:-enable}" = "disable" ]; then + warning "KVM acceleration disabled by user" + kvm_flag="" +elif [ -c "/dev/kvm" ] && [ -w "/dev/kvm" ]; then + info "KVM acceleration enabled" + kvm_flag="-enable-kvm" +else + warning "KVM acceleration not available (is kvm module loaded?)" + kvm_flag="" +fi + +# Run in QEMU +if [[ ${QEMU_FLAGS} == *-S* ]]; then + info "Running OS in QEMU with GDB debugging enabled" + info "To connect GDB, run: gdb" + info "At the GDB prompt, type: target remote localhost:1234" +else + info "Running OS in QEMU..." +fi + +exec qemu-system-x86_64 -M q35 \ + ${kvm_flag} \ + -cdrom "$build_dir/image.iso" \ + -boot d \ + -m 2G \ + -serial stdio \ + -no-reboot \ + -no-shutdown \ + ${QEMU_FLAGS:-}