From 147702a8faade2254544385d35cdb35540d2176b Mon Sep 17 00:00:00 2001 From: mtgmonkey Date: Tue, 29 Jul 2025 09:46:44 -0400 Subject: [PATCH] init --- Cargo.lock | 375 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 33 ++++ asm/boot.asm | 143 +++++++++++++++ asm/long_mode_init.asm | 19 ++ asm/multiboot_header.asm | 15 ++ flake.lock | 108 +++++++++++ flake.nix | 35 ++++ link-cfg/grub.cfg | 7 + link-cfg/linker.ld | 12 ++ package.nix | 75 ++++++++ src/alloc/mod.rs | 10 ++ src/lib.rs | 33 ++++ src/vga/mod.rs | 137 ++++++++++++++ x86_64-oxidos.json | 18 ++ 14 files changed, 1020 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 asm/boot.asm create mode 100644 asm/long_mode_init.asm create mode 100644 asm/multiboot_header.asm create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 link-cfg/grub.cfg create mode 100644 link-cfg/linker.ld create mode 100644 package.nix create mode 100644 src/alloc/mod.rs create mode 100644 src/lib.rs create mode 100644 src/vga/mod.rs create mode 100644 x86_64-oxidos.json diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..976f66c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,375 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" +dependencies = [ + "cpp_demangle", + "fallible-iterator", + "gimli", + "memmap2", + "object", + "rustc-demangle", + "smallvec", + "typed-arena", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cpp_demangle" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dlmalloc" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa3a2dbee57b69fbb5dbe852fa9c0925697fb0c7fbcb1593e90e5ffaedf13d51" +dependencies = [ + "cfg-if", + "libc", + "windows-sys", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "fortanix-sgx-abi" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efc85edd5b83e8394f4371dd0da6859dff63dd387dab8568fece6af4cde6f84" + +[[package]] +name = "getopts" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "gimli" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" +dependencies = [ + "libc", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "object" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +dependencies = [ + "flate2", + "memchr", + "ruzstd", +] + +[[package]] +name = "oxidos" +version = "0.1.0" +dependencies = [ + "addr2line", + "cfg-if", + "dlmalloc", + "fortanix-sgx-abi", + "getopts", + "hashbrown", + "hermit-abi", + "lazy_static", + "object", + "r-efi", + "r-efi-alloc", + "rustc-demangle", + "rustc-literal-escaper", + "spin 0.10.0", + "unwinding", + "wasi", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi-alloc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2f58ef3ca9bb0f9c44d9aa8537601bcd3df94cc9314a40178cadf7d4466354" +dependencies = [ + "r-efi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + +[[package]] +name = "rustc-literal-escaper" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" + +[[package]] +name = "ruzstd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "twox-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "unwinding" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" +dependencies = [ + "gimli", + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..96c8873 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "oxidos" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +lazy_static = { version = "1.5.0", features = ["spin_no_std"] } +spin = { version = "0.10.0", default-features = false, features = ["spin_mutex"] } + +[dev-dependencies] +addr2line = "=0.25.0" +cfg-if = "=1.0.1" +dlmalloc = "=0.2.10" +fortanix-sgx-abi = "=0.6.1" +getopts = "=0.2.23" +hashbrown = "=0.15.4" +hermit-abi = "=0.5.2" +object = "=0.37.1" +r-efi = "=5.3.0" +r-efi-alloc = "=2.1.0" +rustc-demangle = "=0.1.25" +rustc-literal-escaper = "=0.0.5" +unwinding = "=0.2.7" +wasi = "0.11.0" + +[profile.release] +panic="abort" + +[profile.dev] +panic="abort" diff --git a/asm/boot.asm b/asm/boot.asm new file mode 100644 index 0000000..5d38f17 --- /dev/null +++ b/asm/boot.asm @@ -0,0 +1,143 @@ +global start + +extern long_mode_start + +section .text +bits 32 + +start: + mov esp, stack_top ; stack + mov edi, ebx ; move multiboot pointer to edi + + ; error suite + call check_multiboot + call check_cpuid + call check_long_mode + + ; paging + call set_up_page_tables + call enable_paging + + ; 64-bit gdt + lgdt [gdt64.pointer] + jmp gdt64.code:long_mode_start ; change cs to gdt64 and long jump + +set_up_page_tables: + mov eax, p3_table ; map p3_table's address to the first entry in p4_table + or eax, 0b11 ; present, writable + mov [p4_table], eax ; p4_table's first entry points to p3_table + + mov eax, p2_table ; sim. + or eax, 0b11 + mov [p3_table], eax + + mov ecx, 0 ; counter + .map_p2_table: + mov eax, 0x200000 ; 2MiB for a huge page + mul ecx ; destination is ax register + or eax, 0b10000011 ; huge ..... present, writable + mov [p2_table + ecx * 8], eax ; map entry + + inc ecx ; scuffed for-loop section + cmp ecx, 512 + jne .map_p2_table + + ret + +enable_paging: + mov eax, p4_table + mov cr3, eax ; load p4_table to cr3, where it lives + + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax ; set PAE flag in cr4 + + mov ecx, 0xC0000080 + rdmsr + or eax, 1 << 8 + wrmsr ; set long bit in MSR + + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax ; set paging bit in cr0 + ret + +; # | error +; 0 | .no_multiboot +; 1 | .no_cpuid +; 2 | .no_long_mode +error: ; prints RE:R . is used to store error codes + mov dword [0xb8000], 0x4f524f45 + mov dword [0xb8004], 0x4f3a4f52 + mov dword [0xb8008], 0x4f204f20 + mov byte [0xb800a], al + hlt + +check_multiboot: + cmp eax, 0x36d76289 ; eax magic value + jne .no_multiboot + ret +.no_multiboot: + mov al, "0" + jmp error + +check_cpuid: ; check if cpuid flag is supported + pushfd + pop eax ; put flags into eax + + mov ecx, eax ; copy to ecx + xor eax, 1 << 21 ; flip the ID bit + + push eax + popfd ; return eax to flags + + pushfd + pop eax ; put flags to eax again + + push ecx + popfd ; restore flags to old version + + cmp eax, ecx + je .no_cpuid + ret +.no_cpuid: + mov al, "1" + jmp error + +check_long_mode: ; checks ensure cpu is new enough to be 64 bit + mov eax, 0x80000000 + cpuid + cmp eax, 0x80000001 + jb .no_long_mode + + mov eax, 0x80000001 + cpuid + test edx, 1 << 29 + jz .no_long_mode + ret +.no_long_mode: + mov al, "2" + jmp error + +section .bss ; GRUB initialises this to 0 + +align 4096 ; tables must be aligned +p4_table: + resb 4096 +p3_table: + resb 4096 +p2_table: + resb 4096 + +stack_bottom: + resb 4096 * 4 ; 16kB +stack_top: + +section .rodata +gdt64: + dq 0 ; null +.code: equ $ - gdt64 ; code offset + dq (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53) ; code +.pointer: + dw $ - gdt64 - 1 ; $ is .pointer here; length of gdt + dq gdt64 ; pointer to gdt table diff --git a/asm/long_mode_init.asm b/asm/long_mode_init.asm new file mode 100644 index 0000000..1b5b95a --- /dev/null +++ b/asm/long_mode_init.asm @@ -0,0 +1,19 @@ +global long_mode_start + +section .text +bits 64 + +long_mode_start: + mov ax, 0 + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + extern rust_main ; make the jump to Rust! + call rust_main + + mov rax, 0x2f592f412f4b2f4f + mov qword [0xb8000], rax + hlt diff --git a/asm/multiboot_header.asm b/asm/multiboot_header.asm new file mode 100644 index 0000000..8fb6a00 --- /dev/null +++ b/asm/multiboot_header.asm @@ -0,0 +1,15 @@ +section .multiboot_header +header_start: + dd 0xe85250d6 ; magic number multiboot 2 + dd 0 ; magic number protected mode i386 + dd header_end - header_start ; header length + ; checksum + dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) + + ; multiboot tags + + ; end tag + dw 0 ; type + dw 0 ; flags + dd 8 ; size +header_end: diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b979267 --- /dev/null +++ b/flake.lock @@ -0,0 +1,108 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "naersk", + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1752475459, + "narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=", + "owner": "nix-community", + "repo": "fenix", + "rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "naersk": { + "inputs": { + "fenix": "fenix", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1752689277, + "narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=", + "owner": "nix-community", + "repo": "naersk", + "rev": "0e72363d0938b0208d6c646d10649164c43f4d64", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1753549186, + "narHash": "sha256-Znl7rzuxKg/Mdm6AhimcKynM7V3YeNDIcLjBuoBcmNs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "17f6bd177404d6d43017595c5264756764444ab8", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "naersk": "naersk", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1752428706, + "narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "591e3b7624be97e4443ea7b5542c191311aa141d", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1753671061, + "narHash": "sha256-IU4eBWfe9h2QejJYST+EAlhg8a1H6mh9gbcmWgZ2/mQ=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "40065d17ee4dbec3ded8ca61236132aede843fab", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..022117e --- /dev/null +++ b/flake.nix @@ -0,0 +1,35 @@ +{ + inputs = { + nixpkgs.url = "nixpkgs/nixos-unstable"; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + outputs = { + nixpkgs, + naersk, + rust-overlay, + ... + }: let + system = "x86_64-linux"; + overlays = [(import rust-overlay)]; + pkgs = import nixpkgs { + inherit system overlays; + }; + in { + packages.${system} = { + default = + pkgs.callPackage ./package.nix {inherit naersk;}; + }; + devShells.${system}.default = pkgs.mkShell { + packages = [ + pkgs.rust-bin.nightly.latest.default + ]; + }; + }; +} diff --git a/link-cfg/grub.cfg b/link-cfg/grub.cfg new file mode 100644 index 0000000..5960670 --- /dev/null +++ b/link-cfg/grub.cfg @@ -0,0 +1,7 @@ +set timeout=0 +set default=0 + +menuentry "oxidos_boot" { + multiboot2 /boot/kernel.bin + boot +} diff --git a/link-cfg/linker.ld b/link-cfg/linker.ld new file mode 100644 index 0000000..fd54e9e --- /dev/null +++ b/link-cfg/linker.ld @@ -0,0 +1,12 @@ +ENTRY(start) +SECTIONS { + . = 1M; + .boot : + { + KEEP(*(.multiboot_header)) + } + .text : + { + *(.text) + } +} diff --git a/package.nix b/package.nix new file mode 100644 index 0000000..61d7d5b --- /dev/null +++ b/package.nix @@ -0,0 +1,75 @@ +{ + callPackage, + grub2, + naersk, + nasm, + qemu, + rust-bin, + xorriso, + ... +}: let + nightly = rust-bin.nightly.latest.default.override { + extensions = ["rust-src"]; + }; + naersk' = callPackage naersk { + cargo = nightly; + rustc = nightly; + }; + target = builtins.readFile ./x86_64-oxidos.json; +in + naersk'.buildPackage { + name = "oxidos"; + src = ./.; + + copyBins = false; + release = true; + + cargoBuildOptions = x: x ++ ["-Z" "build-std=core,compiler_builtins,alloc" "-Z" "build-std-features=compiler-builtins-mem" "--target=x86_64-oxidos.json"]; + + buildInputs = [ + qemu + ]; + nativeBuildInputs = [ + grub2 + nasm + xorriso + ]; + + preBuild = '' + cat << EOF > x86_64-oxidos.json + ${target} + EOF + ''; + postInstall = '' + nasm -f elf64 asm/multiboot_header.asm -o multiboot_header.asm.o + nasm -f elf64 asm/long_mode_init.asm -o long_mode_init.asm.o + nasm -f elf64 asm/boot.asm -o boot.asm.o + + ld -n -o kernel.bin\ + --gc-sections\ + -T link-cfg/linker.ld\ + multiboot_header.asm.o\ + long_mode_init.asm.o\ + boot.asm.o\ + target/x86_64-oxidos/release/liboxidos.a + + mkdir isofiles/boot/grub -p + cp kernel.bin isofiles/boot/kernel.bin + cp link-cfg/grub.cfg isofiles/boot/grub/grub.cfg + + grub-mkrescue -o os.iso isofiles + + echo "#!/usr/bin/env bash" > oxidos + echo "${qemu}/bin/qemu-system-x86_64 -cdrom $(echo $out)/os.iso" >> oxidos + chmod +x oxidos + + mkdir $out/bin -p + cp oxidos $out/bin/oxidos + cp os.iso $out/os.iso + ''; + + meta = { + mainProgram = "oxidos"; + homepage = "https://mtgmonkey.net"; + }; + } diff --git a/src/alloc/mod.rs b/src/alloc/mod.rs new file mode 100644 index 0000000..12b01fe --- /dev/null +++ b/src/alloc/mod.rs @@ -0,0 +1,10 @@ +use core::alloc::{GlobalAlloc, Layout}; +use core::ptr::null_mut; + +pub struct Allocator; +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + return null_mut(); + } + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5e293d5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +use crate::alloc::Allocator; + +mod alloc; +mod vga; + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator {}; + +#[unsafe(no_mangle)] +pub extern "C" fn rust_main(multiboot_information_address: usize) { + loop { + println!("this"); + println!("is"); + println!("a"); + println!("multi"); + println!("line"); + println!("test"); + println!("that"); + println!("goes"); + println!("on"); + println!("forever"); + } +} + +#[panic_handler] +fn panic(_: &PanicInfo) -> ! { + loop {} +} diff --git a/src/vga/mod.rs b/src/vga/mod.rs new file mode 100644 index 0000000..966ca5b --- /dev/null +++ b/src/vga/mod.rs @@ -0,0 +1,137 @@ +use core::fmt; +use lazy_static::lazy_static; +use spin; + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::vga::_print(format_args!($($arg)*))); +} + +pub fn _print(args: fmt::Arguments) { + use core::fmt::Write; + WRITER.lock().write_fmt(args).unwrap(); +} + +lazy_static! { + pub static ref WRITER: spin::Mutex = spin::Mutex::new(Writer { + column_position: 0, + color_code: ColorCode::new(Color::Pink, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + }); +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum Color { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + Pink = 13, + Yellow = 14, + White = 15, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +struct ColorCode(u8); +impl ColorCode { + fn new(fg: Color, bg: Color) -> ColorCode { + ColorCode((bg as u8) << 4 | (fg as u8)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +struct ScreenChar { + ascii_character: u8, + color_code: ColorCode, +} + +const BUFFER_HEIGHT: usize = 25; +const BUFFER_WIDTH: usize = 80; + +#[repr(transparent)] +struct Buffer { + chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +pub struct Writer { + column_position: usize, + color_code: ColorCode, + buffer: &'static mut Buffer, +} +impl Writer { + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.new_line(), + byte => { + if self.column_position >= BUFFER_WIDTH { + self.new_line(); + } + + let row = BUFFER_HEIGHT - 1; + let col = self.column_position; + + let color_code = self.color_code; + self.buffer.chars[row][col] = ScreenChar { + ascii_character: byte, + color_code, + }; + self.column_position += 1; + } + } + } + + pub fn write_string(&mut self, s: &str) { + for byte in s.bytes() { + match byte { + 0x20..=0x7e | b'\n' => self.write_byte(byte), + _ => self.write_byte(0xfe), + } + } + } + + fn new_line(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col]; + self.buffer.chars[row - 1][col] = character; + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.column_position = 0; + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + ascii_character: b' ', + color_code: self.color_code, + }; + for col in 0..BUFFER_WIDTH { + self.buffer.chars[row][col] = blank; + } + } +} +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_string(s); + Ok(()) + } +} diff --git a/x86_64-oxidos.json b/x86_64-oxidos.json new file mode 100644 index 0000000..19fa504 --- /dev/null +++ b/x86_64-oxidos.json @@ -0,0 +1,18 @@ +{ +"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, + +"features": "-mmx,-sse,+soft-float", +"rustc-abi": "x86-softfloat", + +"disable-redzone": true, +"panic-strategy": "abort", + +"linker-flavor": "gcc" +}