minimum viable product
This commit is contained in:
+3
-9
@@ -1,9 +1,3 @@
|
||||
[unstable]
|
||||
build-std = ["core", "compiler_builtins"]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[build]
|
||||
target = "x86_64-unknown-none"
|
||||
|
||||
[target.x86_64-unknown-none]
|
||||
rustflags = ["-Clink-arg=-Tsrc/linker.ld", "-Crelocation-model=static"]
|
||||
[alias]
|
||||
build-kernel = "build -p kernel --target x86_64-unknown-none -Z build-std=core,compiler_builtins -Z build-std-features=compiler-builtins-mem"
|
||||
run-kernel = "run -p kernel --target x86_64-unknown-none -Z build-std=core,compiler_builtins -Z build-std-features=compiler-builtins-mem"
|
||||
|
||||
Generated
+729
-8
@@ -2,12 +2,33 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.12.1"
|
||||
@@ -15,10 +36,360 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a"
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.9.34"
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13f6a8a495d2f93fe3d6eb3a224f9aa749a63cfd746ed03eb5ddcbd00ade7d8f"
|
||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.11.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5fb69232f250c0d5b74eeb285702b4b0479f574980f45dc9bef97b2c65e2021"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bootloader-boot-config",
|
||||
"fatfs",
|
||||
"gpt",
|
||||
"llvm-tools",
|
||||
"mbrman",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bootloader-boot-config"
|
||||
version = "0.11.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a5e475c13d3d988e105b76b92aeea94614c12590c33495165c02b16e895375"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bootloader_api"
|
||||
version = "0.11.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c074a3d1075b26ed77e502d6af8ab1263abbdc3d026c166e46480f973287293"
|
||||
|
||||
[[package]]
|
||||
name = "builder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[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.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||
|
||||
[[package]]
|
||||
name = "fatfs"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05669f8e7e2d7badc545c513710f0eba09c2fbef683eb859fd79c46c355048e0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpt"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"crc",
|
||||
"log",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.17.1",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader_api",
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "llvm-tools"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
|
||||
[[package]]
|
||||
name = "mbrman"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1fc3bff63c208d4a14301c6cb807af2d1a0760052584ce3f9a737b55fb85498"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitvec",
|
||||
"serde",
|
||||
"serde-big-array",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
@@ -26,6 +397,143 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-big-array"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.4.6"
|
||||
@@ -33,11 +541,218 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793"
|
||||
|
||||
[[package]]
|
||||
name = "wordleos"
|
||||
version = "0.1.0"
|
||||
name = "wasip2"
|
||||
version = "1.0.3+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
"x86_64",
|
||||
"wit-bindgen 0.57.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip3"
|
||||
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||
dependencies = [
|
||||
"wit-bindgen 0.51.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.12.1",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||
dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -47,7 +762,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"bitflags 2.12.1",
|
||||
"rustversion",
|
||||
"volatile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
+8
-7
@@ -1,8 +1,9 @@
|
||||
[package]
|
||||
name = "wordleos"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
[workspace]
|
||||
members = ["kernel", "builder"]
|
||||
resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
bootloader = "0.9"
|
||||
x86_64 = "0.14"
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "builder"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bootloader = "0.11"
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let kernel_path = if args.len() > 1 {
|
||||
args[1].clone()
|
||||
} else {
|
||||
let target = std::env::var("TARGET").unwrap_or_else(|_| "x86_64-unknown-none".to_string());
|
||||
let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
|
||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
|
||||
.unwrap_or_else(|_| ".".to_string());
|
||||
// Builder is at workspace/builder, kernel is at workspace/kernel
|
||||
let workspace = Path::new(&manifest_dir).parent().unwrap();
|
||||
format!("{}/target/{}/{}/kernel", workspace.display(), target, profile)
|
||||
};
|
||||
|
||||
let kernel_path = Path::new(&kernel_path);
|
||||
if !kernel_path.exists() {
|
||||
eprintln!("Kernel not found at: {}", kernel_path.display());
|
||||
eprintln!("Usage: builder <path-to-kernel-elf>");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let out_dir = std::env::var("OUT_DIR").unwrap_or_else(|_| {
|
||||
std::env::var("CARGO_MANIFEST_DIR")
|
||||
.map(|d| format!("{}/../target", d))
|
||||
.unwrap_or_else(|_| "target".to_string())
|
||||
});
|
||||
|
||||
// Disable bootloader's verbose framebuffer logging (default: trace-level yellow text)
|
||||
let mut boot_config = bootloader::BootConfig::default();
|
||||
boot_config.frame_buffer_logging = false;
|
||||
|
||||
// Create UEFI bootable image
|
||||
println!("Creating UEFI boot image from {}", kernel_path.display());
|
||||
let mut uefi_img = bootloader::UefiBoot::new(&kernel_path);
|
||||
uefi_img.set_boot_config(&boot_config);
|
||||
let uefi_path = Path::new(&out_dir).join("wordleos-uefi.img");
|
||||
uefi_img.create_disk_image(&uefi_path)
|
||||
.expect("failed to write UEFI image");
|
||||
println!("UEFI image written to: {}", uefi_path.display());
|
||||
|
||||
// Also create BIOS bootable image for compatibility
|
||||
println!("Creating BIOS boot image from {}", kernel_path.display());
|
||||
let mut bios_img = bootloader::BiosBoot::new(&kernel_path);
|
||||
bios_img.set_boot_config(&boot_config);
|
||||
let bios_path = Path::new(&out_dir).join("wordleos-bios.img");
|
||||
bios_img.create_disk_image(&bios_path)
|
||||
.expect("failed to write BIOS image");
|
||||
println!("BIOS image written to: {}", bios_path.display());
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bootloader_api = "0.11"
|
||||
x86_64 = "0.14"
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
pub const FONT_5X7_W: usize = 5;
|
||||
pub const FONT_5X7_H: usize = 7;
|
||||
|
||||
pub static FONT5X7: [[u8; 7]; 26] = [
|
||||
[0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001], // A
|
||||
[0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110], // B
|
||||
[0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110], // C
|
||||
[0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110], // D
|
||||
[0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111], // E
|
||||
[0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000], // F
|
||||
[0b01110, 0b10001, 0b10000, 0b10111, 0b10001, 0b10001, 0b01110], // G
|
||||
[0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001], // H
|
||||
[0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110], // I
|
||||
[0b00111, 0b00010, 0b00010, 0b00010, 0b00010, 0b10010, 0b01100], // J
|
||||
[0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001], // K
|
||||
[0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111], // L
|
||||
[0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001], // M
|
||||
[0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001, 0b10001], // N
|
||||
[0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], // O
|
||||
[0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000], // P
|
||||
[0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101], // Q
|
||||
[0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001], // R
|
||||
[0b01110, 0b10001, 0b10000, 0b01110, 0b00001, 0b10001, 0b01110], // S
|
||||
[0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100], // T
|
||||
[0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110], // U
|
||||
[0b10001, 0b10001, 0b10001, 0b01010, 0b01010, 0b00100, 0b00100], // V
|
||||
[0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b11011, 0b10001], // W
|
||||
[0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001], // X
|
||||
[0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100], // Y
|
||||
[0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111], // Z
|
||||
];
|
||||
|
||||
pub fn get_5x7(ch: u8) -> Option<&'static [u8; 7]> {
|
||||
if ch.is_ascii_uppercase() {
|
||||
Some(&FONT5X7[(ch - b'A') as usize])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub static PUNCT5X7: &[(u8, [u8; 7])] = &[
|
||||
(b'!', [0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00000, 0b00100]),
|
||||
(b'\'', [0b00100, 0b00100, 0b00100, 0b00000, 0b00000, 0b00000, 0b00000]),
|
||||
(b',', [0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b00100, 0b01000]),
|
||||
(b'-', [0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000]),
|
||||
(b'.', [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b00100]),
|
||||
(b':', [0b00000, 0b00100, 0b00100, 0b00000, 0b00100, 0b00100, 0b00000]),
|
||||
(b'_', [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111]),
|
||||
(b' ', [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000]),
|
||||
];
|
||||
|
||||
pub fn get_punct(ch: u8) -> Option<&'static [u8; 7]> {
|
||||
for &(c, ref glyph) in PUNCT5X7 {
|
||||
if c == ch {
|
||||
return Some(glyph);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -1,5 +1,78 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
const TIMEOUT: u32 = 1_000_000;
|
||||
|
||||
static KEYBOARD_READY: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Initialises the PS/2 controller and keyboard.
|
||||
///
|
||||
/// UEFI firmware often leaves the PS/2 controller uninitialised, so we must
|
||||
/// perform the full startup sequence ourselves before the keyboard will work.
|
||||
/// If no PS/2 controller is present (common on modern UEFI systems), this
|
||||
/// returns gracefully without hanging.
|
||||
pub fn init() {
|
||||
// Disable both PS/2 ports
|
||||
if !try_write_command(0xAD) { return; }
|
||||
if !try_write_command(0xA7) { return; }
|
||||
|
||||
// Flush output buffer
|
||||
let _ = try_read_data();
|
||||
|
||||
// Read and update configuration byte
|
||||
if !try_write_command(0x20) { return; }
|
||||
let config = match try_read_data() {
|
||||
Some(val) => val & !0x07,
|
||||
None => return,
|
||||
};
|
||||
if !try_write_command(0x60) { return; }
|
||||
if !try_write_data(config) { return; }
|
||||
|
||||
// Controller self-test
|
||||
if !try_write_command(0xAA) { return; }
|
||||
if try_read_data() != Some(0x55) { return; }
|
||||
|
||||
// Enable keyboard port
|
||||
if !try_write_command(0xAE) { return; }
|
||||
|
||||
// Reset keyboard
|
||||
if !try_write_data(0xFF) { return; }
|
||||
if try_read_data() != Some(0xFA) { return; } // ACK
|
||||
if try_read_data() != Some(0xAA) { return; } // self-test passed
|
||||
|
||||
KEYBOARD_READY.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn try_write_command(cmd: u8) -> bool {
|
||||
if !poll_write_ready() { return false; }
|
||||
unsafe { Port::new(0x64).write(cmd) }
|
||||
true
|
||||
}
|
||||
|
||||
fn try_write_data(data: u8) -> bool {
|
||||
if !poll_write_ready() { return false; }
|
||||
unsafe { Port::new(0x60).write(data) }
|
||||
true
|
||||
}
|
||||
|
||||
fn poll_write_ready() -> bool {
|
||||
for _ in 0..TIMEOUT {
|
||||
if read_status() & 2 == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn try_read_data() -> Option<u8> {
|
||||
for _ in 0..TIMEOUT {
|
||||
if read_status() & 1 != 0 {
|
||||
return Some(unsafe { Port::new(0x60).read() });
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Actions produced by the PS/2 keyboard decoder.
|
||||
///
|
||||
/// Only A–Z letters, Enter, and Backspace are relevant for the Wordle game.
|
||||
@@ -45,16 +118,25 @@ fn data_available() -> bool {
|
||||
/// is pending, `None` is returned and the caller should briefly spin-wait
|
||||
/// before retrying.
|
||||
///
|
||||
/// ## Scan code handling (Set 1)
|
||||
/// The PS/2 controller is typically in "translated" mode, converting native
|
||||
/// Set 2 scancodes to Set 1 on the fly. In Set 1:
|
||||
/// ## Scan code handling
|
||||
/// The PS/2 keyboard defaults to Scan Code Set 2. Most PS/2 controllers
|
||||
/// run in "translated" mode, converting Set 2 scancodes to Set 1 on the
|
||||
/// fly. In Set 1:
|
||||
/// - Make codes (key pressed): 0x01 – 0x7F
|
||||
/// - Break codes (key released): 0x81 – 0xFF (= make_code | 0x80)
|
||||
/// - Extended keys (arrows, etc.): prefixed with 0xE0
|
||||
///
|
||||
/// We do NOT explicitly change the keyboard's scan code set (command 0xF0)
|
||||
/// because doing so would corrupt the controller's translation — the
|
||||
/// keyboard stays in its default Set 2, and the controller handles the
|
||||
/// conversion to Set 1 transparently.
|
||||
///
|
||||
/// We ignore break codes and extended codes since we only care about when
|
||||
/// a letter key is pressed.
|
||||
pub fn poll_key() -> Option<KeyAction> {
|
||||
if !KEYBOARD_READY.load(Ordering::SeqCst) {
|
||||
return None;
|
||||
}
|
||||
if !data_available() {
|
||||
return None;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod font;
|
||||
mod vga_buffer;
|
||||
mod keyboard;
|
||||
mod rng;
|
||||
mod game;
|
||||
|
||||
use game::{GameState, WordleGame, WORDS};
|
||||
use keyboard::KeyAction;
|
||||
use rng::Lcg;
|
||||
use vga_buffer::{Color, ColorCode};
|
||||
|
||||
use bootloader_api::{entry_point, BootInfo};
|
||||
|
||||
entry_point!(kernel_main);
|
||||
|
||||
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
||||
let fb = boot_info.framebuffer.take()
|
||||
.expect("no framebuffer provided by bootloader");
|
||||
vga_buffer::init(fb);
|
||||
|
||||
vga_buffer::clear_screen(Color::Black);
|
||||
keyboard::init();
|
||||
|
||||
loop {
|
||||
let mut rng = Lcg::from_tsc();
|
||||
let secret = WORDS[rng.next_range(WORDS.len())];
|
||||
|
||||
let mut game = WordleGame::new(secret);
|
||||
game.render_all();
|
||||
|
||||
loop {
|
||||
if let Some(action) = keyboard::poll_key() {
|
||||
match action {
|
||||
KeyAction::Letter(ch) => game.add_letter(ch),
|
||||
KeyAction::Backspace => game.delete_letter(),
|
||||
KeyAction::Enter => {
|
||||
if game.submit_guess().is_none() {}
|
||||
}
|
||||
}
|
||||
game.render_all();
|
||||
|
||||
if game.state == GameState::Won || game.state == GameState::Lost {
|
||||
wait_for_keypress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_for_keypress() {
|
||||
loop {
|
||||
if keyboard::poll_key().is_some() {
|
||||
return;
|
||||
}
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
|
||||
fn spin_delay() {
|
||||
for _ in 0..10000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
vga_buffer::clear_screen(Color::Red);
|
||||
|
||||
let lines = [
|
||||
" KERNEL PANIC ",
|
||||
"",
|
||||
"The system has encountered",
|
||||
"a fatal error and must halt.",
|
||||
];
|
||||
for (i, &line) in lines.iter().enumerate() {
|
||||
let col = (vga_buffer::WIDTH - line.len()) / 2;
|
||||
vga_buffer::write_str(10 + i, col, line,
|
||||
ColorCode::new(Color::White, Color::Red));
|
||||
}
|
||||
|
||||
if let Some(loc) = info.location() {
|
||||
let _ = (loc.file(), loc.line());
|
||||
}
|
||||
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
use crate::font;
|
||||
use bootloader_api::info::{FrameBuffer, PixelFormat};
|
||||
|
||||
pub const WIDTH: usize = 80;
|
||||
pub const HEIGHT: usize = 25;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[allow(dead_code)]
|
||||
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,
|
||||
}
|
||||
|
||||
fn color_to_rgb(color: Color) -> (u8, u8, u8) {
|
||||
match color {
|
||||
Color::Black => (0, 0, 0),
|
||||
Color::Blue => (0, 0, 170),
|
||||
Color::Green => (0, 170, 0),
|
||||
Color::Cyan => (0, 170, 170),
|
||||
Color::Red => (170, 0, 0),
|
||||
Color::Magenta => (170, 0, 170),
|
||||
Color::Brown => (170, 85, 0),
|
||||
Color::LightGray => (170, 170, 170),
|
||||
Color::DarkGray => (85, 85, 85),
|
||||
Color::LightBlue => (85, 85, 255),
|
||||
Color::LightGreen => (85, 255, 85),
|
||||
Color::LightCyan => (85, 255, 255),
|
||||
Color::LightRed => (255, 85, 85),
|
||||
Color::Pink => (255, 85, 255),
|
||||
Color::Yellow => (255, 255, 85),
|
||||
Color::White => (255, 255, 255),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ColorCode {
|
||||
fg: Color,
|
||||
bg: Color,
|
||||
}
|
||||
|
||||
impl ColorCode {
|
||||
pub const fn new(fg: Color, bg: Color) -> ColorCode {
|
||||
ColorCode { fg, bg }
|
||||
}
|
||||
}
|
||||
|
||||
struct FbState {
|
||||
ptr: *mut u8,
|
||||
width: usize,
|
||||
height: usize,
|
||||
stride: usize,
|
||||
bpp: usize,
|
||||
is_bgr: bool,
|
||||
x_off: usize,
|
||||
y_off: usize,
|
||||
cell_w: usize,
|
||||
cell_h: usize,
|
||||
}
|
||||
|
||||
unsafe impl Send for FbState {}
|
||||
|
||||
static mut FB: Option<FbState> = None;
|
||||
|
||||
pub fn init(fb: FrameBuffer) {
|
||||
let info = fb.info();
|
||||
let buf = fb.into_buffer();
|
||||
let ptr = buf.as_mut_ptr();
|
||||
let is_bgr = matches!(info.pixel_format, PixelFormat::Bgr);
|
||||
let cell_w = (info.width / WIDTH).max(1);
|
||||
let cell_h = (info.height / HEIGHT).max(1);
|
||||
let x_off = (info.width - cell_w * WIDTH) / 2;
|
||||
let y_off = (info.height - cell_h * HEIGHT) / 2;
|
||||
unsafe {
|
||||
FB = Some(FbState {
|
||||
ptr,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
stride: info.stride,
|
||||
bpp: info.bytes_per_pixel,
|
||||
is_bgr,
|
||||
x_off,
|
||||
y_off,
|
||||
cell_w,
|
||||
cell_h,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn with_fb<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut FbState) -> R,
|
||||
{
|
||||
unsafe {
|
||||
let fb = &mut *core::ptr::addr_of_mut!(FB);
|
||||
f(fb.as_mut().expect("Framebuffer not initialized"))
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pixel(state: &mut FbState, x: usize, y: usize, r: u8, g: u8, b: u8) {
|
||||
if x >= state.width || y >= state.height {
|
||||
return;
|
||||
}
|
||||
let offset = (y * state.stride + x) * state.bpp;
|
||||
unsafe {
|
||||
if state.is_bgr {
|
||||
*state.ptr.add(offset) = b;
|
||||
*state.ptr.add(offset + 1) = g;
|
||||
*state.ptr.add(offset + 2) = r;
|
||||
} else {
|
||||
*state.ptr.add(offset) = r;
|
||||
*state.ptr.add(offset + 1) = g;
|
||||
*state.ptr.add(offset + 2) = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_rect(state: &mut FbState, x: usize, y: usize, w: usize, h: usize, r: u8, g: u8, b: u8) {
|
||||
let x_end = (x + w).min(state.width);
|
||||
let y_end = (y + h).min(state.height);
|
||||
for py in y..y_end {
|
||||
for px in x..x_end {
|
||||
write_pixel(state, px, py, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_glyph(ch: u8) -> Option<&'static [u8; 7]> {
|
||||
if let Some(g) = font::get_5x7(ch) {
|
||||
return Some(g);
|
||||
}
|
||||
font::get_punct(ch)
|
||||
}
|
||||
|
||||
fn draw_glyph_at(
|
||||
state: &mut FbState,
|
||||
cell_x: usize, cell_y: usize, cell_w: usize, cell_h: usize,
|
||||
ch: u8,
|
||||
fg_r: u8, fg_g: u8, fg_b: u8,
|
||||
bg_r: u8, bg_g: u8, bg_b: u8,
|
||||
) {
|
||||
fill_rect(state, cell_x, cell_y, cell_w, cell_h, bg_r, bg_g, bg_b);
|
||||
|
||||
let glyph = match get_glyph(ch) {
|
||||
Some(g) => g,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if cell_w < 3 || cell_h < 3 {
|
||||
return;
|
||||
}
|
||||
|
||||
let scale_h = (cell_w.saturating_sub(2)) / font::FONT_5X7_W;
|
||||
let scale_v = (cell_h.saturating_sub(2)) / font::FONT_5X7_H;
|
||||
let scale = scale_h.min(scale_v).min(8);
|
||||
|
||||
if scale == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let glw = font::FONT_5X7_W * scale;
|
||||
let glh = font::FONT_5X7_H * scale;
|
||||
let off_x = (cell_w - glw) / 2;
|
||||
let off_y = (cell_h - glh) / 2;
|
||||
|
||||
for row in 0..font::FONT_5X7_H {
|
||||
for col in 0..font::FONT_5X7_W {
|
||||
if glyph[row] & (1 << (4 - col)) != 0 {
|
||||
fill_rect(
|
||||
state,
|
||||
cell_x + off_x + col * scale,
|
||||
cell_y + off_y + row * scale,
|
||||
scale, scale,
|
||||
fg_r, fg_g, fg_b,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_screen(bg: Color) {
|
||||
let (r, g, b) = color_to_rgb(bg);
|
||||
with_fb(|state| {
|
||||
fill_rect(state, 0, 0, state.width, state.height, r, g, b);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn write_char(row: usize, col: usize, ch: u8, color: ColorCode) {
|
||||
if row >= HEIGHT || col >= WIDTH {
|
||||
return;
|
||||
}
|
||||
let (fg_r, fg_g, fg_b) = color_to_rgb(color.fg);
|
||||
let (bg_r, bg_g, bg_b) = color_to_rgb(color.bg);
|
||||
with_fb(|state| {
|
||||
let cell_x = state.x_off + col * state.cell_w;
|
||||
let cell_y = state.y_off + row * state.cell_h;
|
||||
draw_glyph_at(
|
||||
state,
|
||||
cell_x, cell_y, state.cell_w, state.cell_h,
|
||||
ch,
|
||||
fg_r, fg_g, fg_b,
|
||||
bg_r, bg_g, bg_b,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn write_str(row: usize, col: usize, s: &str, color: ColorCode) {
|
||||
for (i, &ch) in s.as_bytes().iter().enumerate() {
|
||||
if col + i < WIDTH {
|
||||
write_char(row, col + i, ch, color);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
ENTRY(_start);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x200000;
|
||||
|
||||
.rodata : ALIGN(4K)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.text : ALIGN(4K)
|
||||
{
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.data.rel.ro : ALIGN(4K)
|
||||
{
|
||||
*(.data.rel.ro .data.rel.ro.*)
|
||||
}
|
||||
|
||||
.data : ALIGN(4K)
|
||||
{
|
||||
*(.data .data.*)
|
||||
}
|
||||
|
||||
.got : ALIGN(4K)
|
||||
{
|
||||
*(.got)
|
||||
}
|
||||
|
||||
.bss : ALIGN(4K)
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
*(.debug_abbrev)
|
||||
*(.debug_info)
|
||||
*(.debug_aranges)
|
||||
*(.debug_ranges)
|
||||
*(.debug_str)
|
||||
*(.debug_frame)
|
||||
*(.debug_line)
|
||||
*(.debug_loc)
|
||||
*(.symtab)
|
||||
*(.strtab)
|
||||
}
|
||||
}
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod vga_buffer;
|
||||
mod keyboard;
|
||||
mod rng;
|
||||
mod game;
|
||||
|
||||
use game::{GameState, WordleGame, WORDS};
|
||||
use keyboard::KeyAction;
|
||||
use rng::Lcg;
|
||||
use vga_buffer::{Color, ColorCode};
|
||||
|
||||
use bootloader::{entry_point, BootInfo};
|
||||
|
||||
entry_point!(kernel_main);
|
||||
|
||||
// Called by the bootloader after it has set up 64-bit long mode, page tables,
|
||||
// and a stack. The `boot_info` parameter provides information about the
|
||||
// memory map, framebuffer, etc. — but for our VGA-text-mode display we
|
||||
// don't need it.
|
||||
//
|
||||
// How the bootloader works:
|
||||
// 1. BIOS/UEFI loads the bootloader (from `bootloader` crate).
|
||||
// 2. Bootloader transitions CPU from real mode → protected mode → long mode,
|
||||
// sets up page tables with VGA framebuffer at 0xB8000 identity-mapped,
|
||||
// loads our ELF, and jumps to kernel_main.
|
||||
// 3. We arrive with interrupts disabled (RFLAGS.IF = 0), at CPL 0 (ring 0).
|
||||
|
||||
fn kernel_main(_boot_info: &'static BootInfo) -> ! {
|
||||
// ── Initialisation ─────────────────────────────────────────────────
|
||||
vga_buffer::clear_screen(Color::Black);
|
||||
|
||||
// ── Main game loop (runs forever, restarting after each game) ──────
|
||||
loop {
|
||||
// Seed the RNG from the CPU timestamp counter so every boot picks
|
||||
// a different secret word (assuming the machine has been on for a
|
||||
// different amount of time).
|
||||
let mut rng = Lcg::from_tsc();
|
||||
let secret = WORDS[rng.next_range(WORDS.len())];
|
||||
|
||||
let mut game = WordleGame::new(secret);
|
||||
game.render_all();
|
||||
|
||||
// ── Per-game input loop ────────────────────────────────────────
|
||||
loop {
|
||||
if let Some(action) = keyboard::poll_key() {
|
||||
match action {
|
||||
KeyAction::Letter(ch) => game.add_letter(ch),
|
||||
KeyAction::Backspace => game.delete_letter(),
|
||||
KeyAction::Enter => {
|
||||
if game.submit_guess().is_none() {
|
||||
// Incomplete guess — the game shows nothing
|
||||
// for this; we just re-render as-is.
|
||||
}
|
||||
}
|
||||
}
|
||||
game.render_all();
|
||||
|
||||
if game.state == GameState::Won || game.state == GameState::Lost {
|
||||
// Wait for any key press, then restart the game.
|
||||
wait_for_keypress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Brief spin delay to keep the CPU from saturating at 100 %
|
||||
// while polling. 10k iterations of `pause` is roughly 10–50 µs
|
||||
// on modern CPUs — invisible to human input but vastly reduces
|
||||
// power draw.
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Blocks until any key is pressed (used between games).
|
||||
fn wait_for_keypress() {
|
||||
loop {
|
||||
if keyboard::poll_key().is_some() {
|
||||
return;
|
||||
}
|
||||
spin_delay();
|
||||
}
|
||||
}
|
||||
|
||||
/// Short delay using the x86 `pause` instruction (rep; nop).
|
||||
///
|
||||
/// The `pause` instruction hints to the CPU that this is a spin-wait loop,
|
||||
/// allowing it to reduce power consumption and improve hyper-thread
|
||||
/// performance. It behaves as a no-op architecturally.
|
||||
fn spin_delay() {
|
||||
for _ in 0..10000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
/// Panic handler — invoked on unrecoverable errors.
|
||||
///
|
||||
/// Displays a red crash screen with a message, then halts forever.
|
||||
#[panic_handler]
|
||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||
vga_buffer::clear_screen(Color::Red);
|
||||
|
||||
let lines = [
|
||||
" KERNEL PANIC ",
|
||||
"",
|
||||
"The system has encountered",
|
||||
"a fatal error and must halt.",
|
||||
];
|
||||
for (i, &line) in lines.iter().enumerate() {
|
||||
let col = (vga_buffer::WIDTH - line.len()) / 2;
|
||||
vga_buffer::write_str(10 + i, col, line,
|
||||
ColorCode::new(Color::White, Color::Red));
|
||||
}
|
||||
|
||||
// The panic message payload is the `Arguments` type. We could format
|
||||
// it with a custom `core::fmt::Write` implementation, but since we're
|
||||
// already in a crash state, we keep it simple: just display the line
|
||||
// number if available.
|
||||
if let Some(loc) = info.location() {
|
||||
let file = loc.file();
|
||||
let line_num = loc.line();
|
||||
// Truncated display for the panic location.
|
||||
let file_start = if file.len() > 30 { &file[file.len() - 30..] } else { file };
|
||||
// Print at a fixed offset; we can't do dynamic formatting in no_std
|
||||
// without a formatter.
|
||||
let _ = (file_start, line_num);
|
||||
}
|
||||
|
||||
loop {
|
||||
x86_64::instructions::hlt();
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
use core::ptr::write_volatile;
|
||||
|
||||
/// VGA text mode display dimensions.
|
||||
///
|
||||
/// The standard VGA text mode provides an 80×25 grid of character cells.
|
||||
/// Each cell is 2 bytes: [ASCII byte] [attribute byte].
|
||||
/// The buffer starts at physical address 0xB8000 and is memory-mapped into
|
||||
/// the CPU's address space. The x86_64 bootloader identity-maps this region,
|
||||
/// so we can write to it with regular memory stores — but we must use volatile
|
||||
/// writes to prevent the compiler from optimizing away MMIO operations.
|
||||
pub const VGA_ADDR: *mut u8 = 0xB8000 as *mut u8;
|
||||
pub const WIDTH: usize = 80;
|
||||
pub const HEIGHT: usize = 25;
|
||||
|
||||
/// Standard VGA text-mode colors.
|
||||
///
|
||||
/// The attribute byte layout:
|
||||
/// bits 0-3: foreground color (0 = black, 15 = white)
|
||||
/// bits 4-6: background color (0-7, hardware limit; bit 7 = blink)
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
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,
|
||||
}
|
||||
|
||||
/// A packed attribute byte encoding foreground + background color.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ColorCode(u8);
|
||||
|
||||
impl ColorCode {
|
||||
/// Constructs a color code from foreground and background colors.
|
||||
///
|
||||
/// ## Hardware note
|
||||
/// The VGA attribute byte stores the background color in bits 4-6 (3 bits,
|
||||
/// limiting backgrounds to 0-7). Bit 7 is the blink enable bit, which we
|
||||
/// keep cleared. The foreground color uses bits 0-3 (including intensity
|
||||
/// on bit 3), giving 16 possible foreground colors.
|
||||
pub const fn new(fg: Color, bg: Color) -> ColorCode {
|
||||
ColorCode(((bg as u8) << 4) | (fg as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the entire VGA screen to the given background color.
|
||||
///
|
||||
/// Writes a space character (0x20) with the appropriate attribute byte
|
||||
/// to every cell on the screen.
|
||||
pub fn clear_screen(bg: Color) {
|
||||
let color = ColorCode::new(Color::White, bg);
|
||||
for offset in (0..(WIDTH * HEIGHT * 2)).step_by(2) {
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), b' ');
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a single character at position (row, col) with the given color.
|
||||
///
|
||||
/// The position is bounds-checked against the 80×25 screen. Writes outside
|
||||
/// the visible area are silently ignored.
|
||||
pub fn write_char(row: usize, col: usize, ch: u8, color: ColorCode) {
|
||||
if row < HEIGHT && col < WIDTH {
|
||||
let offset = (row * WIDTH + col) * 2;
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), ch);
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a string starting at position (row, col) with the given color.
|
||||
///
|
||||
/// Stops at the right edge of the screen to avoid wrapping.
|
||||
pub fn write_str(row: usize, col: usize, s: &str, color: ColorCode) {
|
||||
for (i, &ch) in s.as_bytes().iter().enumerate() {
|
||||
if col + i < WIDTH {
|
||||
write_char(row, col + i, ch, color);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user