From a2cca0be4eb34c477900104abd17f6be9d38b0d4 Mon Sep 17 00:00:00 2001 From: Matthieu Jolimaitre Date: Fri, 25 Oct 2024 01:44:27 +0200 Subject: [PATCH] add basic script repl --- .cargo/config.toml | 2 +- Cargo.lock | 516 +++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + setup | 9 + src/dev/alloc.rs | 6 - src/dev/console.rs | 39 ++-- src/dev/input.rs | 36 +-- src/dev/memory.rs | 116 ++++++++++ src/dev/mod.rs | 2 +- src/hard/int.rs | 17 +- src/hard/keyboard.rs | 277 ++++++++++++++++++++++- src/main.rs | 24 +- src/program/mod.rs | 1 + src/program/shell.rs | 51 +++++ src/util.rs | 4 + 15 files changed, 1041 insertions(+), 61 deletions(-) delete mode 100644 src/dev/alloc.rs create mode 100644 src/dev/memory.rs create mode 100644 src/program/mod.rs create mode 100644 src/program/shell.rs create mode 100644 src/util.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 357ec76..5a5a72c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,7 +3,7 @@ target = ["x86_64-nulfos.json"] [unstable] -build-std = ["core", "compiler_builtins"] +build-std = ["core", "compiler_builtins", "alloc"] build-std-features = ["compiler-builtins-mem"] [target.'cfg(target_os = "none")'] diff --git a/Cargo.lock b/Cargo.lock index dfaf80c..6f5201c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,33 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "autocfg" version = "1.4.0" @@ -20,12 +47,74 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blinkcast" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87be723831f9bfa47f0bc5b28edd97cbd8002726289d8bfd6dfdc1cd895e06d9" +dependencies = [ + "loom", +] + [[package]] name = "bootloader" version = "0.9.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "365861702868e2a37b4247aaecc7bd8f4389baec8d025497ad8ba7ff37ee9440" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chumsky" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[package]] +name = "generator" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb949699c3e4df3a183b1d2142cb24277057055ed23c68ed58894f76c517223" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "foldhash", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -35,6 +124,18 @@ dependencies = [ "spin", ] +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -54,18 +155,86 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "microlang" +version = "0.1.0" +source = "git+https://git.barnulf.net/mb/microlang.git#3868298f006b58dd1df2c4d615e044d5698846f7" +dependencies = [ + "chumsky", + "hashbrown 0.15.0", + "libm", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "nulfos" version = "0.1.0" dependencies = [ + "blinkcast", "bootloader", "lazy_static", "linked_list_allocator", + "microlang", "pic8259", "spin", "x86_64", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pic8259" version = "0.11.0" @@ -75,18 +244,107 @@ dependencies = [ "x86_64", ] +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rustversion" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "spin" version = "0.9.8" @@ -105,12 +363,250 @@ dependencies = [ "lock_api", ] +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "volatile" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "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" + [[package]] name = "x86_64" version = "0.15.1" @@ -122,3 +618,23 @@ dependencies = [ "rustversion", "volatile", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 6c3d150..2c1b345 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ linked_list_allocator = "0.10.5" pic8259 = "0.11.0" spin = "0.9.8" x86_64 = "0.15.1" +microlang = { git = "https://git.barnulf.net/mb/microlang.git" } +blinkcast = "0.2.0" # artefact configuration diff --git a/setup b/setup index ecf7d2c..6c09a47 100755 --- a/setup +++ b/setup @@ -4,3 +4,12 @@ set -e rustup target add x86_64-unknown-none rustup component add rust-src rustup component add llvm-tools-preview + +if ! cargo bootimage --help > /dev/null 2>&1 +then echo " +WARNING cargo-bootimage is not installed. + Get it from your package manager or run : + + cargo install cargo-bootimage +" && exit 1 +fi \ No newline at end of file diff --git a/src/dev/alloc.rs b/src/dev/alloc.rs deleted file mode 100644 index 705348d..0000000 --- a/src/dev/alloc.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::println; - -pub fn init() { - println!("Initializing Allocator."); - // TODO -} diff --git a/src/dev/console.rs b/src/dev/console.rs index 2d04943..fc48faf 100644 --- a/src/dev/console.rs +++ b/src/dev/console.rs @@ -1,7 +1,7 @@ use core::fmt; use lazy_static::lazy_static; -use spin::Mutex; +use spin::{Mutex, MutexGuard}; use crate::hard::vga::{self, Vga}; @@ -17,12 +17,16 @@ macro_rules! println { } lazy_static! { - static ref Out: Mutex = Mutex::new(Console::init()); + static ref OUT: Mutex = Mutex::new(Console::init()); +} + +pub fn out<'r>() -> MutexGuard<'r, Console> { + OUT.lock() } pub struct Console { - cursor: Cursor, - vga: Vga, + pub cursor: Cursor, + pub vga: Vga, } impl Console { @@ -44,6 +48,11 @@ impl Console { } } } + + pub fn correct(&mut self) { + self.cursor.set_col((self.cursor.col().max(1) - 1)); + self.vga.write_at(self.cursor.pos(), ' '); + } } struct Cursor { @@ -67,14 +76,6 @@ impl Cursor { (self.column, self.line) } - pub fn set_line(&mut self, line: usize) { - self.line = line; - } - - pub fn set_col(&mut self, col: usize) { - self.column = col; - } - pub fn line(&self) -> usize { self.line } @@ -83,6 +84,18 @@ impl Cursor { self.column } + pub fn set_pos(&mut self, pos: (usize, usize)) { + (self.column, self.line) = pos; + } + + pub fn set_line(&mut self, line: usize) { + self.line = line; + } + + pub fn set_col(&mut self, col: usize) { + self.column = col; + } + pub fn progress(&mut self) { self.column += 1; if self.column < self.width { @@ -113,6 +126,6 @@ pub fn print_args(args: fmt::Arguments) { use core::fmt::Write; use x86_64::instructions::interrupts; interrupts::without_interrupts(|| { - Out.lock().write_fmt(args).unwrap(); + OUT.lock().write_fmt(args).unwrap(); }); } diff --git a/src/dev/input.rs b/src/dev/input.rs index 74829d7..92619a4 100644 --- a/src/dev/input.rs +++ b/src/dev/input.rs @@ -1,23 +1,23 @@ -use lazy_static::lazy_static; -use spin::Mutex; +// use lazy_static::lazy_static; +// use spin::Mutex; -use crate::hard::keyboard::Keyboard; +// use crate::hard::keyboard::Keyboard; -lazy_static! { - static ref In: Mutex = Mutex::new(Input::init()); -} +// lazy_static! { +// static ref In: Mutex = Mutex::new(Input::init()); +// } -pub struct Input { - keyboard: Keyboard, -} +// pub struct Input { +// keyboard: Keyboard, +// } -impl Input { - pub fn init() -> Self { - let keyboard = Keyboard; - Self { keyboard } - } +// impl Input { +// pub fn init() -> Self { +// let keyboard = Keyboard; +// Self { keyboard } +// } - pub fn read(out: &mut [char]) -> usize { - 0 - } -} +// pub fn read(out: &mut [char]) -> usize { +// 0 +// } +// } diff --git a/src/dev/memory.rs b/src/dev/memory.rs new file mode 100644 index 0000000..47f9768 --- /dev/null +++ b/src/dev/memory.rs @@ -0,0 +1,116 @@ +use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; +use x86_64::{ + registers::control::Cr3, + structures::paging::{ + mapper::MapToError, page_table::FrameError, FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, + PageTableFlags, PhysFrame, Size4KiB, + }, + PhysAddr, VirtAddr, +}; + +use crate::println; + +pub fn init(physical_memory_start: u64, mapping: &'static MemoryMap) { + let mut mapper = unsafe { init_mapper(physical_memory_start) }; + let mut frame_allocator = unsafe { BootInfoFrameAllocator::new(mapping) }; + init_heap(&mut mapper, &mut frame_allocator).unwrap(); +} + +pub unsafe fn init_mapper(physical_memory_start: u64) -> OffsetPageTable<'static> { + println!("Initializing Mapper."); + let physical_memory_start = VirtAddr::new(physical_memory_start); + let level_4_table = active_level_4_table(physical_memory_start); + OffsetPageTable::new(level_4_table, physical_memory_start) +} + +unsafe fn active_level_4_table(physical_memory_start: VirtAddr) -> &'static mut PageTable { + let (l4_table, _flags) = Cr3::read(); + let l4_start = l4_table.start_address(); + let virt = physical_memory_start + l4_start.as_u64(); + let page_table_ptr = virt.as_mut_ptr::(); + &mut *page_table_ptr +} + +pub struct BootInfoFrameAllocator { + memory_map: &'static MemoryMap, + next: usize, +} + +impl BootInfoFrameAllocator { + pub unsafe fn new(memory_map: &'static MemoryMap) -> Self { + println!("Initializing Frame Allocator."); + BootInfoFrameAllocator { memory_map, next: 0 } + } + + fn usable_frames(&self) -> impl Iterator { + let regions = self.memory_map.iter(); + let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable); + let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr()); + let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096)); + frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr))) + } +} + +unsafe impl FrameAllocator for BootInfoFrameAllocator { + fn allocate_frame(&mut self) -> Option { + let frame = self.usable_frames().nth(self.next); + self.next += 1; + frame + } +} + +pub const HEAP_START: usize = 0x_4444_4444_0000; +pub const HEAP_SIZE: usize = 500 * 1024; // 500 KiB + +pub fn init_heap( + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> Result<(), MapToError> { + println!("Initializing Heap."); + let page_range = { + let heap_start = VirtAddr::new(HEAP_START as u64); + let heap_end = heap_start + HEAP_SIZE as u64 - 1u64; + let heap_start_page = Page::containing_address(heap_start); + let heap_end_page = Page::containing_address(heap_end); + Page::range_inclusive(heap_start_page, heap_end_page) + }; + + for page in page_range { + let frame = frame_allocator + .allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() }; + } + + unsafe { ALLOCATOR.lock().init(HEAP_START as _, HEAP_SIZE) }; + + Ok(()) +} + +use linked_list_allocator::LockedHeap; + +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_start: VirtAddr) -> Option { + translate_addr_inner(addr, physical_memory_start) +} + +fn translate_addr_inner(addr: VirtAddr, physical_memory_start: VirtAddr) -> Option { + let (level_4_table_frame, _) = Cr3::read(); + let table_indexes = [addr.p4_index(), addr.p3_index(), addr.p2_index(), addr.p1_index()]; + let mut frame = level_4_table_frame; + for &index in &table_indexes { + let virt = physical_memory_start + frame.start_address().as_u64(); + let table_ptr: *const PageTable = virt.as_ptr(); + let table = unsafe { &*table_ptr }; + let entry = &table[index]; + frame = match entry.frame() { + Ok(frame) => frame, + Err(FrameError::FrameNotPresent) => return None, + Err(FrameError::HugeFrame) => panic!("huge pages not supported."), + }; + } + Some(frame.start_address() + u64::from(addr.page_offset())) +} diff --git a/src/dev/mod.rs b/src/dev/mod.rs index c2b67ed..3726faa 100644 --- a/src/dev/mod.rs +++ b/src/dev/mod.rs @@ -1,3 +1,3 @@ -pub mod alloc; pub mod console; pub mod input; +pub mod memory; diff --git a/src/hard/int.rs b/src/hard/int.rs index c5a4557..07edb6e 100644 --- a/src/hard/int.rs +++ b/src/hard/int.rs @@ -6,7 +6,7 @@ use x86_64::{ structures::idt::{InterruptDescriptorTable, InterruptStackFrame}, }; -use crate::{print, println}; +use crate::{hard::keyboard::keyboard, println}; pub fn init() { println!("Initializing interrupt handler."); @@ -33,17 +33,12 @@ static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(0x20, 0x2 extern "x86-interrupt" fn keyboard_handler(_stack_frame: InterruptStackFrame) { let mut port = Port::new(0x60); - let _scancode: u8 = unsafe { port.read() }; - // crate::task::keyboard::add_scancode(scancode); - println!("keyboard got scancode"); - unsafe { - PICS.lock().notify_end_of_interrupt(INT_IDX_KEYBOARD); - } + let scan_code = unsafe { port.read() }; + keyboard().record(scan_code); + unsafe { PICS.lock().notify_end_of_interrupt(INT_IDX_KEYBOARD) }; } extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) { - print!("."); - unsafe { - PICS.lock().notify_end_of_interrupt(INT_IDX_TIMER); - } + // print!("."); + unsafe { PICS.lock().notify_end_of_interrupt(INT_IDX_TIMER) }; } diff --git a/src/hard/keyboard.rs b/src/hard/keyboard.rs index 352121d..fd8038f 100644 --- a/src/hard/keyboard.rs +++ b/src/hard/keyboard.rs @@ -1,7 +1,278 @@ -pub struct Keyboard; +use alloc::boxed::Box; +use lazy_static::lazy_static; +use spin::{Mutex, MutexGuard}; + +use crate::println; + +pub fn keyboard<'r>() -> MutexGuard<'r, Keyboard> { + KEYBOARD.lock() +} + +lazy_static! { + static ref KEYBOARD: Mutex = Mutex::new(Keyboard::init()); +} + +pub struct Keyboard { + on_code: Option>, + last: Option, +} impl Keyboard { - pub fn record(key_code: u8) { - // todo!() + pub fn init() -> Self { + let on_code = None; + let last = None; + Self { on_code, last } + } + + pub fn on_code(&mut self, op: impl FnMut(Code) + Send + 'static) { + self.on_code = Some(Box::new(op) as _); + } + + pub fn record(&mut self, scan_code: u8) { + let code = self.parse(scan_code); + match code { + Err(err) => println!("Failed to record key : {err:?}"), + Ok(Code::Control) => self.last = Some(Code::Control), + Ok(c) if let Some(op) = self.on_code.as_mut() => op(c), + Ok(c) => println!("Ignoring {c:?}"), + }; + } + + pub fn parse(&mut self, scan_code: u8) -> Result { + let code = match (self.last, scan_code) { + (None, 0xE0) => Code::Control, + (None, 0x1E) => Code::Down(Key::Char('a')), + (None, 0x30) => Code::Down(Key::Char('b')), + (None, 0x2E) => Code::Down(Key::Char('c')), + (None, 0x20) => Code::Down(Key::Char('d')), + (None, 0x12) => Code::Down(Key::Char('e')), + (None, 0x21) => Code::Down(Key::Char('f')), + (None, 0x22) => Code::Down(Key::Char('g')), + (None, 0x23) => Code::Down(Key::Char('h')), + (None, 0x17) => Code::Down(Key::Char('i')), + (None, 0x24) => Code::Down(Key::Char('j')), + (None, 0x25) => Code::Down(Key::Char('k')), + (None, 0x26) => Code::Down(Key::Char('l')), + (None, 0x32) => Code::Down(Key::Char('m')), + (None, 0x31) => Code::Down(Key::Char('n')), + (None, 0x18) => Code::Down(Key::Char('o')), + (None, 0x19) => Code::Down(Key::Char('p')), + (None, 0x10) => Code::Down(Key::Char('q')), + (None, 0x13) => Code::Down(Key::Char('r')), + (None, 0x1F) => Code::Down(Key::Char('s')), + (None, 0x14) => Code::Down(Key::Char('t')), + (None, 0x16) => Code::Down(Key::Char('u')), + (None, 0x2F) => Code::Down(Key::Char('v')), + (None, 0x11) => Code::Down(Key::Char('w')), + (None, 0x2D) => Code::Down(Key::Char('x')), + (None, 0x15) => Code::Down(Key::Char('y')), + (None, 0x2C) => Code::Down(Key::Char('z')), + (None, 0x0B) => Code::Down(Key::Char('0')), + (None, 0x02) => Code::Down(Key::Char('1')), + (None, 0x03) => Code::Down(Key::Char('2')), + (None, 0x04) => Code::Down(Key::Char('3')), + (None, 0x05) => Code::Down(Key::Char('4')), + (None, 0x06) => Code::Down(Key::Char('5')), + (None, 0x07) => Code::Down(Key::Char('6')), + (None, 0x08) => Code::Down(Key::Char('7')), + (None, 0x09) => Code::Down(Key::Char('8')), + (None, 0x0A) => Code::Down(Key::Char('9')), + (None, 0x29) => Code::Down(Key::Char('`')), + (None, 0x0C) => Code::Down(Key::Char('-')), + (None, 0x0D) => Code::Down(Key::Char('=')), + (None, 0x2B) => Code::Down(Key::Char('\\')), + (None, 0x1A) => Code::Down(Key::Char('[')), + (None, 0x34) => Code::Down(Key::Char('.')), + (None, 0x35) => Code::Down(Key::Char('/')), + (None, 0x1B) => Code::Down(Key::Char(']')), + (None, 0x27) => Code::Down(Key::Char(';')), + (None, 0x28) => Code::Down(Key::Char('\'')), + (None, 0x33) => Code::Down(Key::Char(',')), + (None, 0x1C) => Code::Down(Key::Char('\n')), + (None, 0x39) => Code::Down(Key::Char(' ')), + (None, 0x0F) => Code::Down(Key::Char('\t')), + (None, 0x0E) => Code::Down(Key::BackSpace), + (None, 0x9E) => Code::Up(Key::Char('a')), + (None, 0xB0) => Code::Up(Key::Char('b')), + (None, 0xAE) => Code::Up(Key::Char('c')), + (None, 0xA0) => Code::Up(Key::Char('d')), + (None, 0x92) => Code::Up(Key::Char('e')), + (None, 0xA1) => Code::Up(Key::Char('f')), + (None, 0xA2) => Code::Up(Key::Char('g')), + (None, 0xA3) => Code::Up(Key::Char('h')), + (None, 0x97) => Code::Up(Key::Char('i')), + (None, 0xA4) => Code::Up(Key::Char('j')), + (None, 0xA5) => Code::Up(Key::Char('k')), + (None, 0xA6) => Code::Up(Key::Char('l')), + (None, 0xB2) => Code::Up(Key::Char('m')), + (None, 0xB1) => Code::Up(Key::Char('n')), + (None, 0x98) => Code::Up(Key::Char('o')), + (None, 0x99) => Code::Up(Key::Char('p')), + (None, 0x90) => Code::Up(Key::Char('q')), + (None, 0x93) => Code::Up(Key::Char('r')), + (None, 0x9F) => Code::Up(Key::Char('s')), + (None, 0x94) => Code::Up(Key::Char('t')), + (None, 0x96) => Code::Up(Key::Char('u')), + (None, 0xAF) => Code::Up(Key::Char('v')), + (None, 0x91) => Code::Up(Key::Char('w')), + (None, 0xAD) => Code::Up(Key::Char('x')), + (None, 0x95) => Code::Up(Key::Char('y')), + (None, 0xAC) => Code::Up(Key::Char('z')), + (None, 0x8B) => Code::Up(Key::Char('0')), + (None, 0x82) => Code::Up(Key::Char('1')), + (None, 0x83) => Code::Up(Key::Char('2')), + (None, 0x84) => Code::Up(Key::Char('3')), + (None, 0x85) => Code::Up(Key::Char('4')), + (None, 0x86) => Code::Up(Key::Char('5')), + (None, 0x87) => Code::Up(Key::Char('6')), + (None, 0x88) => Code::Up(Key::Char('7')), + (None, 0x89) => Code::Up(Key::Char('8')), + (None, 0x8A) => Code::Up(Key::Char('9')), + (None, 0xA9) => Code::Up(Key::Char('`')), + (None, 0x8C) => Code::Up(Key::Char('-')), + (None, 0x8D) => Code::Up(Key::Char('=')), + (None, 0xAB) => Code::Up(Key::Char('\\')), + (None, 0x9A) => Code::Up(Key::Char('[')), + (None, 0xB4) => Code::Up(Key::Char('.')), + (None, 0xB5) => Code::Up(Key::Char('/')), + (None, 0x9B) => Code::Up(Key::Char(']')), + (None, 0xA7) => Code::Up(Key::Char(';')), + (None, 0xA8) => Code::Up(Key::Char('\'')), + (None, 0xB3) => Code::Up(Key::Char(',')), + (None, 0x9C) => Code::Up(Key::Char('\n')), + (None, 0xB9) => Code::Up(Key::Char(' ')), + (None, 0x8F) => Code::Up(Key::Char('\t')), + (None, 0x8E) => Code::Up(Key::BackSpace), + _ => Err(KeyParseErr::UnknownCode(scan_code))?, + }; + Ok(code) } } + +#[derive(Debug, Clone, Copy)] +pub enum Code { + Down(Key), + Up(Key), + Control, +} + +#[derive(Debug, Clone, Copy)] +pub enum Key { + Char(char), + BackSpace, +} + +#[derive(Debug, Clone, Copy)] +pub enum KeyParseErr { + UnknownCode(u8), +} + +/* + +char table + +A 1E 9E +B 30 B0 +C 2E AE +D 20 A0 +E 12 92 +F 21 A1 +G 22 A2 +H 23 A3 +I 17 97 +J 24 A4 +K 25 A5 +L 26 A6 +M 32 B2 +N 31 B1 +O 18 98 +P 19 99 +Q 10 90 +R 13 93 +S 1F 9F +T 14 94 +U 16 96 +V 2F AF +W 11 91 +X 2D AD +Y 15 95 +Z 2C AC +0 0B 8B +1 02 82 +2 03 83 +3 04 84 +4 05 85 +5 06 86 +6 07 87 +7 08 88 +8 09 89 +9 0A 8A +` 29 89 +- 0C 8C += 0D 8D +\ 2B AB +[ 1A 9A +. 34 B4 +/ 35 B5 +] 1B 9B +; 27 A7 +' 28 A8 +, 33 B3 +ENTER 1C 9C +SPACE 39 B9 +TAB 0F 8F + +BKSP 0E 8E +ESC 01 81 +CAPS 3A BA +L_SHFT 2A AA +L_CTRL 1D 9D +INSERT E0,52 E0,D2 +HOME E0,47 E0,97 +PG_UP E0,49 E0,C9 +DELETE E0,53 E0,D3 +END E0,4F E0,CF +PG_DN E0,51 E0,D1 +U_ARROW E0,48 E0,C8 +L_ARROW E0,4B E0,CB +D_ARROW E0,50 E0,D0 +R_ARROW E0,4D E0,CD +L_GUI E0,5B E0,DB +L_ALT 38 B8 +R_SHFT 36 B6 +R_CTRL E0,1D E0,9D +R_GUI E0,5C E0,DC +R_ALT E0,38 E0,B8 +APPS E0,5D E0,DD +F1 3B BB +F2 3C BC +F3 3D BD +F4 3E BE +F5 3F BF +F6 40 C0 +F7 41 C1 +F8 42 C2 +F9 43 C3 +F10 44 C4 +F11 57 D7 +F12 58 D8 +SCROLL 46 C6 +KP_2 50 D0 +KP_3 51 D1 +KP_4 4B CB +KP_5 4C CC +KP_6 4D CD +KP_7 47 C7 +KP_8 48 C8 +KP_9 49 C9 +NUM 45 C5 +KP_/ E0,35 E0,B5 +KP_* 37 B7 +KP_- 4A CA +KP_+ 4E CE +KP_EN E0,1C E0,9C +KP_. 53 D3 +KP_0 52 D2 +KP_1 4F CF + +*/ diff --git a/src/main.rs b/src/main.rs index d6ffdc5..6c8d049 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,34 @@ #![no_std] #![no_main] #![feature(abi_x86_interrupt)] +#![feature(if_let_guard)] +extern crate alloc; mod dev; mod hard; +mod program; +mod util; use core::panic::PanicInfo; +use program::shell; -use dev::alloc; +use bootloader::{entry_point, BootInfo}; +use dev::memory; use hard::int; -#[no_mangle] -pub extern "C" fn _start() -> ! { +entry_point!(kernel_main); + +fn kernel_main(boot_info: &'static BootInfo) -> ! { println!("Starting."); int::init(); - alloc::init(); + memory::init(boot_info.physical_memory_offset, &boot_info.memory_map); println!("Finished initializations."); - loop {} + shell::main(); + panic!("Exiting.") } #[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - println!("Paniced."); - loop {} +fn panic(info: &PanicInfo) -> ! { + println!("Panicked : {info:?}"); + util::spin(); } diff --git a/src/program/mod.rs b/src/program/mod.rs new file mode 100644 index 0000000..327cf1b --- /dev/null +++ b/src/program/mod.rs @@ -0,0 +1 @@ +pub mod shell; diff --git a/src/program/shell.rs b/src/program/shell.rs new file mode 100644 index 0000000..f610c61 --- /dev/null +++ b/src/program/shell.rs @@ -0,0 +1,51 @@ +use core::mem; + +use alloc::{string::String, sync::Arc}; +use blinkcast::alloc::channel; +use microlang::Context; +use spin::Mutex; + +use crate::{ + dev::console::out, + hard::keyboard::{keyboard, Code, Key}, + print, println, +}; + +pub fn main() { + let (tx, mut rx) = channel(1024); + + let buff = Arc::new(Mutex::new(String::new())); + keyboard().on_code(move |c| { + let mut buff = buff.lock(); + match c { + Code::Down(Key::Char(c)) => { + print!("{c}"); + if c == '\n' { + let mut new = String::new(); + mem::swap(&mut new, &mut buff); + tx.send(new); + } else { + buff.push(c); + } + } + Code::Down(Key::BackSpace) => { + out().correct(); + buff.pop(); + } + _ => (), + } + }); + + let mut context = Context::empty(); + + print!("> "); + loop { + if let Some(line) = rx.recv() { + match context.eval(line) { + Ok((_, value)) => println!("{}", value.serialize()), + Err(err) => println!("Error: {err:?}"), + } + print!("> "); + } + } +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..87c30af --- /dev/null +++ b/src/util.rs @@ -0,0 +1,4 @@ +#[allow(clippy::empty_loop)] +pub fn spin() -> ! { + loop {} +}