commit 7612fba1e4accec5ec29d35f5bcfd74bd1558bf3 Author: pjht Date: Mon Sep 9 09:44:51 2024 -0500 Initial commit diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..bec4b7a --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "x86_64-unknown-mikros" + +[install] +root = "../os_build/sysroot" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..08ad91a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,529 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[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 = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bga" +version = "0.1.0" +dependencies = [ + "dev_driver_rpc", + "devfs_rpc", + "file_rpc", + "fontdue", + "itertools", + "parking_lot", + "pci_rpc", + "rhexdump", + "syslog_rpc", + "volatile 0.6.1", + "x86_64", +] + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "critical-section" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" + +[[package]] +name = "dev_driver_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "devfs_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "file_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "serde", +] + +[[package]] +name = "fontdue" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe23d02309319171d00d794c9ff48d4f903c0e481375b1b04b017470838af04" +dependencies = [ + "hashbrown", + "ttf-parser", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[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 = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pci_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", +] + +[[package]] +name = "postcard" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "postcard-derive", + "serde", +] + +[[package]] +name = "postcard-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0239fa9c1d225d4b7eb69925c25c5e082307a141e470573fbbe3a817ce6a7a37" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +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 = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rhexdump" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a92cbe1a3dd221e3777fef339115d3b85e17a538668e03a0f3ae9c6a98351c7" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syslog_rpc" +version = "0.1.0" +dependencies = [ + "parking_lot", + "postcard", + "syslog_structs", +] + +[[package]] +name = "syslog_structs" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[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 = "volatile" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8ca9a5d4debca0633e697c88269395493cebf2e10db21ca2dbde37c1356452" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df" +dependencies = [ + "bit_field", + "bitflags", + "rustversion", + "volatile 0.4.6", +] + +[[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 2.0.77", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..156a15c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "bga" +version = "0.1.0" +edition = "2021" + +[dependencies] +dev_driver_rpc = { version = "0.1.0", path = "../dev_driver_rpc" } +devfs_rpc = { version = "0.1.0", path = "../devfs/devfs_rpc" } +file_rpc = { version = "0.1.0", path = "../file_rpc" } +fontdue = { version = "0.9.2", default-features = false, features = ["hashbrown"] } +itertools = "0.13.0" +parking_lot = "0.12.3" +pci_rpc = { version = "0.1.0", path = "../pci/pci_rpc" } +rhexdump = "0.2.0" +syslog_rpc = { version = "0.1.0", path = "../syslog/syslog_rpc" } +volatile = { version = "0.6.1", features = ["unstable"] } +x86_64 = "0.15.1" diff --git a/FiraCode-Regular.ttf b/FiraCode-Regular.ttf new file mode 100644 index 0000000..bd73685 Binary files /dev/null and b/FiraCode-Regular.ttf differ diff --git a/edid.rs b/edid.rs new file mode 100644 index 0000000..39476be --- /dev/null +++ b/edid.rs @@ -0,0 +1,57 @@ + //let mut edid = [0; 1024]; + // + //let edid_vol = unsafe { + // VolatilePtr::new(NonNull::slice_from_raw_parts( + // NonNull::new(reg_base).unwrap(), + // 1024, + // )) + //}; + // + //edid_vol.copy_into_slice(&mut edid); + // + //rhexdump!(&edid); + // + //if edid[35] & 0xC0 > 0 { + // println!("Established timing 720x400"); + //} + //if edid[35] & 0x3C > 0 { + // println!("Established timing 640x480"); + //} + //if (edid[35] & 0x3 > 0) | (edid[36] & 0xC0 > 0) { + // println!("Established timing 800x600"); + //} + //if edid[36] & 0x20 > 0 { + // println!("Established timing 832x624"); + //} + //if edid[36] & 0x1E > 0 { + // println!("Established timing 1024x768"); + //} + //if edid[36] & 0x1 > 0 { + // println!("Established timing 1280x1024"); + //} + //if edid[37] & 0x80 > 0 { + // println!("Established timing 1152x870"); + //} + // + //for i in 0..7 { + // let offset = 38 + 2 * i; + // let xres = ((edid[offset] as u32) + 31) * 8; + // let aspect = (edid[offset] & 0xC0) >> 6; + // let yres = match aspect { + // 0 => (xres / 16) * 10, + // 1 => (xres / 4) * 3, + // 2 => (xres / 5) * 4, + // 3 => (xres / 16) * 9, + // _ => panic!("Invalid aspect!"), + // }; + // println!("Standard res {i}: {xres}x{yres}"); + //} + // + //for (i, offset) in [0x36, 0x48, 0x5A, 0x6C].iter().enumerate() { + // let xres = edid[offset + 2] as u32 | ((edid[offset + 4] as u32 & 0xF0) << 4); + // if xres == 0 { + // continue; + // } + // let yres = edid[offset + 5] as u32 | ((edid[offset + 7] as u32 & 0xF0) << 4); + // println!("Detailed res {i}: {xres}x{yres}"); + //} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..a5535e3 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "dev-x86_64-unknown-mikros" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d272886 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,420 @@ +#![warn(clippy::pedantic)] +#![allow(clippy::cast_lossless)] +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] +#![allow(clippy::cast_precision_loss)] +#![allow(clippy::cast_sign_loss)] +#![allow(clippy::match_same_arms)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::similar_names)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::wildcard_imports)] +#![allow(clippy::cast_ptr_alignment)] +#![warn(clippy::nursery)] +#![allow(clippy::suspicious_operation_groupings)] +#![allow(clippy::option_if_let_else)] +#![allow(clippy::non_send_fields_in_send_ty)] +#![allow(clippy::missing_const_for_fn)] +#![allow(clippy::while_float)] +#![allow(clippy::tuple_array_conversions)] + +use core::str; +use std::{ + borrow::Cow, collections::HashMap, fmt::{self, Write}, os::mikros::{address_space::ACTIVE_SPACE, ipc, syscalls} +}; + +use fontdue::{layout::{CoordinateSystem, GlyphRasterConfig, Layout, LayoutSettings, TextStyle, WrapStyle}, Font, FontSettings}; +use itertools::Itertools; +use parking_lot::Mutex; +use x86_64::structures::paging::PageTableFlags; + +#[allow(unused)] +const VBE_ID_NUM: usize = 0; +#[allow(unused)] +const VBE_XRES_NUM: usize = 1; +#[allow(unused)] +const VBE_YRES_NUM: usize = 2; +#[allow(unused)] +const VBE_BPP_NUM: usize = 3; +#[allow(unused)] +const VBE_ENABLE_NUM: usize = 4; +#[allow(unused)] +const VBE_BANK_NUM: usize = 5; +#[allow(unused)] +const VBE_VIRT_WIDTH_NUM: usize = 6; +#[allow(unused)] +const VBE_VIRT_HEIGHT_NUM: usize = 7; +#[allow(unused)] +const VBE_INDEX_X_NUM: usize = 8; +#[allow(unused)] +const VBE_INDEX_Y_NUM: usize = 9; + +const BGA_MMIO_VBE_OFFSET: usize = 0x500; + +pub struct Bga { + mmio_base: *mut u8, + framebuffer_base: *mut u8, + draw_buffer: Vec, + scroll_offset: usize, + xres: usize, + yres: usize, +} + + +unsafe impl Send for Bga {} +unsafe impl Sync for Bga {} + +impl Bga { + pub unsafe fn new(mmio_base: *mut u8, framebuffer_base: *mut u8) -> Self { + Self { mmio_base, framebuffer_base, draw_buffer: Vec::new(), scroll_offset: 0, xres: 0, yres: 0} + } + + // Changes the screenn resolution. Also clears the screen. + pub fn set_resolution(&mut self, xres: u16, yres: u16) { + let vbe_base = self.vbe_base(); + unsafe { + vbe_base.wrapping_add(VBE_ENABLE_NUM).write_volatile(0x0); + vbe_base.wrapping_add(VBE_XRES_NUM).write_volatile(xres); + vbe_base.wrapping_add(VBE_YRES_NUM).write_volatile(yres); + vbe_base.wrapping_add(VBE_BPP_NUM).write_volatile(0x20); + vbe_base.wrapping_add(VBE_ENABLE_NUM).write_volatile(0x41); + } + self.draw_buffer.resize(xres as usize * yres as usize * 4 * 2, 0); + self.draw_buffer.fill(0); + self.scroll_offset = 0; + self.xres = xres as usize; + self.yres = yres as usize; + } + + pub fn clear(&mut self) { + self.draw_buffer.fill(0); + self.scroll_offset = 0; + } + + pub fn set_pixel(&mut self, row: usize, col: usize, value: u8) { + if row >= self.yres || col >= self.xres { + return; + } + let row_offset = self.row_byte_offset(row + self.scroll_offset); + self.draw_buffer[row_offset+col*4..][..4].fill(value); + } + + pub fn update_screen(&mut self) { + let scroll_top_byte_offset = self.row_byte_offset(self.scroll_offset); + let scroll_bot_byte_offset = self.row_byte_offset(self.scroll_offset + self.yres); + let visible_buf = &self.draw_buffer[scroll_top_byte_offset..scroll_bot_byte_offset]; + unsafe { self.framebuffer_base.copy_from_nonoverlapping(&visible_buf[0], visible_buf.len()) }; + } + + fn vbe_base(&self) -> *mut u16 { + self.mmio_base.wrapping_add(BGA_MMIO_VBE_OFFSET).cast::() + } + + fn row_byte_offset(&self, row: usize) -> usize { + 4 * self.xres * row + } + + fn clear_raw_row(&mut self, row: usize) { + if row >= self.yres*2 { + return; + } + let offset = self.row_byte_offset(row); + self.draw_buffer[offset..][..(self.xres * 4)].fill(0); + } + + pub fn clear_row(&mut self, row: usize) { + if row >= self.yres { + return; + } + self.clear_raw_row(row + self.scroll_offset); + } + + // TODO: Explain this function's logic + fn scroll_by(&mut self, offset: usize) { + if offset > self.yres { + return; + } + let old_offset = self.scroll_offset; + self.scroll_offset += offset; + if self.scroll_offset >= self.yres { + for row in (old_offset + self.yres)..(self.yres*2) { + self.clear_raw_row(row); + } + self.scroll_offset -= self.yres; + let half_buf_size = self.row_byte_offset(self.yres); + let (scr_1,scr_2) = self.draw_buffer.split_at_mut(half_buf_size); + scr_1.copy_from_slice(scr_2); + for row in (self.yres)..(self.yres + self.scroll_offset) { + self.clear_raw_row(row); + } + } else { + for row in (old_offset + self.yres)..(self.scroll_offset + self.yres) { + self.clear_raw_row(row); + } + } + } +} + +pub struct FramebufferWriter { + out_string: String, + font: Font, + layout: Layout, + next_line_y: usize, + glyph_cache: HashMap>, + cursor_height: usize, +} + +impl FramebufferWriter { + fn new(font: Font, fbuf: &Bga) -> Self { + let mut layout = Layout::new(CoordinateSystem::PositiveYDown); + layout.reset(&LayoutSettings { + max_width: Some(fbuf.xres as f32), + max_height: Some(fbuf.yres as f32), + wrap_style: WrapStyle::Letter, + ..Default::default() + }); + Self { + out_string: String::new(), + font, + layout, + next_line_y: 0, + glyph_cache: HashMap::new(), + cursor_height: 0, + } + } + + fn update_screen(&mut self, fbuf: &mut Bga) { + self.layout.clear(); + self.layout.append(&[&self.font], &TextStyle::new(&self.out_string, 12.0, 0)); + let text_height = self.layout.height(); + self.layout.append(&[&self.font], &TextStyle::new("\u{2588}", 12.0, 0)); + + if (self.next_line_y + self.layout.height() as usize) > fbuf.yres { + let excess_y = + self.layout.height() as usize - (fbuf.yres - self.next_line_y); + fbuf.scroll_by(excess_y); + self.next_line_y -= excess_y; + } + + for row in 0..usize::max(self.cursor_height+5,text_height as usize) { + fbuf.clear_row(self.next_line_y + row); + } + + //for row in 0..(fbuf.yres - self.next_line_y) { + // fbuf.clear_row(self.next_line_y + row); + //} + + self.cursor_height = (self.layout.height() - text_height) as usize; + + let glyphs = self.layout.glyphs(); + + let mut first_line_top_offset = None; + + for line in self.layout.lines().unwrap() { + if first_line_top_offset.is_none() { + first_line_top_offset = Some((line.baseline_y - line.max_ascent) as usize); + } + let first_line_top_offset = first_line_top_offset.unwrap(); + for glyph_pos in &glyphs[line.glyph_start..=line.glyph_end] { + if glyph_pos.width == 0 || glyph_pos.height == 0 { + continue; + } + let bitmap: Cow<[u8]> = if let Some(bitmap) = self.glyph_cache.get(&glyph_pos.key) { + bitmap.into() + } else { + let bitmap = self.font.rasterize_config(glyph_pos.key).1; + self.glyph_cache.insert(glyph_pos.key, bitmap.clone()); + bitmap.into() + }; + for (i, &pixel) in bitmap.iter().enumerate() { + let row = i / glyph_pos.width; + let col = i % glyph_pos.width; + fbuf.set_pixel( + row + glyph_pos.y as usize - first_line_top_offset + self.next_line_y, + col + glyph_pos.x as usize, + pixel, + ); + } + } + } + + let last_line = self.layout.lines().unwrap().last().unwrap(); + fbuf.update_screen(); + + let first_char_offset = glyphs[last_line.glyph_start].byte_offset; + let last_char_offset = glyphs[last_line.glyph_end -1].byte_offset; + let mut last_char_end = last_char_offset + 1; + while last_char_end < self.out_string.len() && !self.out_string.is_char_boundary(last_char_end) { + last_char_end += 1; + } + let log_line_slice = &self.out_string[first_char_offset..last_char_end]; + + let before_last_height = (last_line.baseline_y - last_line.max_ascent) as usize; + + if self.out_string.ends_with('\n') { + self.out_string.clear(); + self.next_line_y += text_height as usize; + } else { + self.out_string = log_line_slice.to_string(); + self.next_line_y += before_last_height; + } + } +} + +impl fmt::Write for FramebufferWriter { + fn write_char(&mut self, c: char) -> fmt::Result { + self.out_string.push(c); + Ok(()) + } + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.out_string.push_str(s); + Ok(()) + } +} + +struct DevServ; + +impl dev_driver_rpc::Server for DevServ { + fn open(&self, _path: &std::path::Path) -> Result { + Ok(0) + } +} + +struct FileServ { + fbwriter: Mutex, + fbuffer: Mutex, +} + +impl file_rpc::Server for FileServ { + fn read( + &self, + _fd: u64, + _pos: u64, + _len: usize, + ) -> std::result::Result, ()> { + Err(()) + } + + #[allow(clippy::significant_drop_tightening)] + fn write(&self, _fd: u64, _pos: u64, data: &[u8]) -> Result<(), ()> { + let string = str::from_utf8(data).map_err(|_| ())?; + let mut fbwriter = self.fbwriter.lock(); + let mut fbuffer = self.fbuffer.lock(); + let _ = fbwriter.write_str(string); // never errors + fbwriter.update_screen(&mut fbuffer); + Ok(()) + } + + fn close(&self, _fd: u64) {} + + fn size(&self, _fd: u64) -> Option { + None + } +} + +fn main() { + let syslog_pid = loop { + if let Some(pid) = syscalls::try_get_registered(2) { + break pid; + } + }; + let syslog_client = syslog_rpc::Client::new(syslog_pid); + let (bus_str, dev_str, func_str, pci_pid_str, dev_id_str) = std::env::args() + .skip(1) + .collect_tuple::<(_, _, _, _, _)>() + .expect("Usage: bga "); + let bus = bus_str + .parse::() + .unwrap_or_else(|_| panic!("{bus_str:?} is not a valid bus number")); + let dev = dev_str + .parse::() + .unwrap_or_else(|_| panic!("{dev_str:?} is not a valid device number")); + let func = func_str + .parse::() + .unwrap_or_else(|_| panic!("{func_str:?} is not a valid function number")); + let pci_pid = pci_pid_str + .parse::() + .unwrap_or_else(|_| panic!("{pci_pid_str:?} is not a valid PID")); + let dev_id = dev_id_str + .parse::() + .unwrap_or_else(|_| panic!("{dev_id_str:?} is not a valid device ID")); + + syslog_client.send_text_message("bga", format!("Started on PCI device with address: Bus # {bus}, device # {dev}, and function # {func}")).unwrap(); + syslog_client + .send_text_message("bga", format!("PCI driver has PID {pci_pid}")) + .unwrap(); + + let pci_client = pci_rpc::Client::new(pci_pid); + let bars = pci_client.get_bars(bus, dev, func).unwrap(); + + let mmio_base: *mut u8 = unsafe { + ACTIVE_SPACE + .lock() + .unwrap() + .map_free_to( + bars[2].1 as u64, + bars[2].2.div_ceil(4096) as usize, + (PageTableFlags::WRITABLE | PageTableFlags::WRITE_THROUGH).bits(), + ) + .unwrap() + }; + + let framebuffer_base: *mut u8 = unsafe { + ACTIVE_SPACE + .lock() + .unwrap() + .map_free_to( + bars[0].1 as u64, + bars[0].2.div_ceil(4096) as usize, + (PageTableFlags::WRITABLE | PageTableFlags::WRITE_THROUGH).bits(), + ) + .unwrap() + }; + + let vbe_base = mmio_base.wrapping_add(BGA_MMIO_VBE_OFFSET).cast::(); + + let version = unsafe { vbe_base.wrapping_add(VBE_ID_NUM).read_volatile() }; + + syslog_client + .send_text_message("bga", format!("BGA version {version:#x}")) + .unwrap(); + if version != 0xB0C5 { + syslog_client + .send_text_message( + "bga", + "Error: Only compatible with version 0xB0C5, aborting", + ) + .unwrap(); + return; + } + + let mut bga = unsafe { Bga::new(mmio_base, framebuffer_base) }; + + syslog_client + .send_text_message("bga", "Setting resolution to 1920x1050") + .unwrap(); + bga.set_resolution(1920, 1050); + + let font = Font::from_bytes(include_bytes!("../FiraCode-Regular.ttf").as_slice(), FontSettings::default()).unwrap(); + let writer = FramebufferWriter::new(font, &bga); + + dev_driver_rpc::register_server(Box::new(DevServ)); + file_rpc::register_server(Box::new(FileServ { + fbwriter: Mutex::new(writer), + fbuffer: Mutex::new(bga), + })); + let devfs_pid; + loop { + if let Some(pid) = syscalls::try_get_registered(1) { + devfs_pid = pid; + break; + } + } + devfs_rpc::Client::new(devfs_pid) + .register_dev(&format!("bga{dev_id}")) + .unwrap(); + loop { + ipc::process_messages(); + } +}