Merge branch 'msi' into 'master'

Greatly improve xhcid by using real MSI-X irqs.

See merge request redox-os/drivers!59
This commit is contained in:
Jeremy Soller
2020-04-19 15:32:02 +00:00
29 changed files with 3270 additions and 1063 deletions
Generated
+292 -99
View File
@@ -47,8 +47,8 @@ name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -84,6 +84,15 @@ dependencies = [
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.7.0"
@@ -132,6 +141,25 @@ name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chashmap"
version = "2.2.2"
source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#da92c702e052cde00db5e409dfb234af71928152"
dependencies = [
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.33.0"
@@ -164,10 +192,11 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.4.0"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -188,8 +217,8 @@ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -203,10 +232,10 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.7.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -250,6 +279,88 @@ name = "futures"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-channel"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-executor"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-io"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-macro"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures-sink"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-task"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures-util"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gpt"
version = "0.6.3"
@@ -263,10 +374,10 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.1.6"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -328,7 +439,7 @@ name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -367,7 +478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.66"
version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -380,10 +491,19 @@ name = "lock_api"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lock_api"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.3.9"
@@ -410,12 +530,17 @@ name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memoffset"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -435,7 +560,7 @@ dependencies = [
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -454,7 +579,7 @@ dependencies = [
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -468,7 +593,7 @@ version = "0.6.7"
source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999"
dependencies = [
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
]
@@ -489,7 +614,7 @@ version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -502,7 +627,7 @@ dependencies = [
"extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)",
"hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
"ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)",
"pbr 1.0.2 (git+https://github.com/a8m/pb)",
@@ -522,7 +647,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni
dependencies = [
"arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)",
"extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
"ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)",
"pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -589,8 +714,8 @@ name = "num_cpus"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -620,7 +745,7 @@ dependencies = [
[[package]]
name = "owning_ref"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -635,18 +760,42 @@ dependencies = [
"parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parking_lot_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "partitionlib"
version = "0.1.0"
@@ -662,8 +811,8 @@ name = "pbr"
version = "1.0.2"
source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966"
dependencies = [
"crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -674,7 +823,7 @@ name = "pbr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -684,12 +833,15 @@ dependencies = [
name = "pcid"
version = "0.1.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -704,14 +856,29 @@ name = "percent-encoding"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pin-utils"
version = "0.1.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro-hack"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro-nested"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "1.0.8"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -729,10 +896,10 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -741,7 +908,7 @@ version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -796,7 +963,7 @@ name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -808,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -848,6 +1015,16 @@ dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox-log"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#08693d48b2d7b56fcb07a1e62e257bacce749cef"
dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_event"
version = "0.1.0"
@@ -884,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -931,7 +1108,7 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -946,7 +1123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "1.0.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -962,9 +1139,9 @@ name = "scroll_derive"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -983,7 +1160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -995,7 +1172,7 @@ version = "0.32.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1013,30 +1190,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.104"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.104"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.47"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1057,7 +1234,7 @@ name = "smallvec"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1093,11 +1270,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "1.0.14"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1106,7 +1283,7 @@ name = "termion"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1122,20 +1299,20 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.10"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thiserror-impl"
version = "1.0.10"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1143,7 +1320,7 @@ name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1294,7 +1471,7 @@ dependencies = [
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)",
"mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)",
@@ -1303,20 +1480,12 @@ dependencies = [
"tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1403,7 +1572,7 @@ dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"xhcid 0.1.0",
]
@@ -1523,15 +1692,20 @@ name = "xhcid"
version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)",
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pcid 0.1.0",
"plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)",
"redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1544,6 +1718,7 @@ dependencies = [
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
@@ -1552,21 +1727,32 @@ dependencies = [
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "<none>"
"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "<none>"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7"
"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
"checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "<none>"
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273"
"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7"
@@ -1576,14 +1762,16 @@ dependencies = [
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "<none>"
"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
@@ -1601,16 +1789,21 @@ dependencies = [
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402"
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
"checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "<none>"
"checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "<none>"
"checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
@@ -1623,6 +1816,7 @@ dependencies = [
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)" = "<none>"
"checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "<none>"
"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "<none>"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
@@ -1631,10 +1825,10 @@ dependencies = [
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b"
"checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76"
"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
"checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1"
"checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28"
"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a"
@@ -1642,9 +1836,9 @@ dependencies = [
"checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90"
"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
@@ -1653,11 +1847,11 @@ dependencies = [
"checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d"
"checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad"
"checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7"
"checksum thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae"
"checksum thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
@@ -1671,7 +1865,6 @@ dependencies = [
"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "<none>"
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
-1
View File
@@ -1,4 +1,3 @@
use orbclient;
use std::fs::File;
use std::io::Write;
use std::str;
+3 -1
View File
@@ -22,7 +22,7 @@ vendor = 33006
device = 48879
command = ["bgad", "$NAME", "$BAR0"]
#nvmed
# nvmed
[[drivers]]
name = "NVME storage"
class = 1
@@ -37,9 +37,11 @@ vendor = 33006
device = 51966
command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"]
# xhcid
[[drivers]]
name = "XHCI"
class = 12
subclass = 3
interface = 48
command = ["xhcid", "$NAME", "$BAR0", "$IRQ"]
channel_name = "pcid-xhcid"
+1
View File
@@ -0,0 +1 @@
/target
+16 -5
View File
@@ -3,10 +3,21 @@ name = "pcid"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "pcid"
path = "src/main.rs"
[lib]
name = "pcid_interface"
path = "src/lib.rs"
[dependencies]
bitflags = "1.0"
bincode = "1.2"
bitflags = "1"
byteorder = "1.2"
redox_syscall = "0.1"
serde = "1.0"
serde_derive = "1.0"
toml = "0.4"
libc = "0.2"
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "1"
toml = "0.5"
+7 -4
View File
@@ -1,12 +1,14 @@
use std::collections::BTreeMap;
use std::ops::Range;
#[derive(Debug, Default, Deserialize)]
use serde::Deserialize;
#[derive(Clone, Debug, Default, Deserialize)]
pub struct Config {
pub drivers: Vec<DriverConfig>
pub drivers: Vec<DriverConfig>,
}
#[derive(Debug, Default, Deserialize)]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct DriverConfig {
pub name: Option<String>,
pub class: Option<u8>,
@@ -16,5 +18,6 @@ pub struct DriverConfig {
pub vendor: Option<u16>,
pub device: Option<u16>,
pub device_id_range: Option<Range<u16>>,
pub command: Option<Vec<String>>
pub command: Option<Vec<String>>,
pub channel_name: Option<String>,
}
+229
View File
@@ -0,0 +1,229 @@
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::{env, io};
use std::os::unix::io::{FromRawFd, RawFd};
use serde::{Serialize, Deserialize, de::DeserializeOwned};
use thiserror::Error;
pub use crate::pci::PciBar;
pub use crate::pci::msi;
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[repr(u8)]
pub enum LegacyInterruptPin {
/// INTa#
IntA = 1,
/// INTb#
IntB = 2,
/// INTc#
IntC = 3,
/// INTd#
IntD = 4,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PciFunction {
/// Number of PCI bus
pub bus_num: u8,
/// Number of PCI device
pub dev_num: u8,
/// Number of PCI function
pub func_num: u8,
/// PCI Base Address Registers
pub bars: [PciBar; 6],
/// BAR sizes
pub bar_sizes: [u32; 6],
/// Legacy IRQ line
pub legacy_interrupt_line: u8,
/// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all.
pub legacy_interrupt_pin: Option<LegacyInterruptPin>,
/// Vendor ID
pub venid: u16,
/// Device ID
pub devid: u16,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubdriverArguments {
pub func: PciFunction,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum FeatureStatus {
Enabled,
Disabled,
}
impl FeatureStatus {
pub fn enabled(enabled: bool) -> Self {
if enabled {
Self::Enabled
} else {
Self::Disabled
}
}
pub fn is_enabled(&self) -> bool {
if let &Self::Enabled = self { true } else { false }
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum PciFeature {
Msi,
MsiX,
}
impl PciFeature {
pub fn is_msi(&self) -> bool {
if let &Self::Msi = self { true } else { false }
}
pub fn is_msix(&self) -> bool {
if let &Self::MsiX = self { true } else { false }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum PciFeatureInfo {
Msi(msi::MsiCapability),
MsiX(msi::MsixCapability),
}
#[derive(Debug, Error)]
pub enum PcidClientHandleError {
#[error("i/o error: {0}")]
IoError(#[from] io::Error),
#[error("JSON ser/de error: {0}")]
SerializationError(#[from] bincode::Error),
#[error("environment variable error: {0}")]
EnvError(#[from] env::VarError),
#[error("malformed fd: {0}")]
EnvValidityError(std::num::ParseIntError),
#[error("invalid response: {0:?}")]
InvalidResponse(PcidClientResponse),
}
pub type Result<T, E = PcidClientHandleError> = std::result::Result<T, E>;
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PcidClientRequest {
RequestConfig,
RequestFeatures,
EnableFeature(PciFeature),
FeatureStatus(PciFeature),
FeatureInfo(PciFeature),
}
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PcidServerResponseError {
NonexistentFeature(PciFeature),
}
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PcidClientResponse {
Config(SubdriverArguments),
AllFeatures(Vec<(PciFeature, FeatureStatus)>),
FeatureEnabled(PciFeature),
FeatureStatus(PciFeature, FeatureStatus),
Error(PcidServerResponseError),
FeatureInfo(PciFeature, PciFeatureInfo),
}
// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over
// a channel, the communication could potentially be done via mmap, using a channel
// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields
// are stored in the same buffer as the actual data).
/// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`.
pub struct PcidServerHandle {
pcid_to_client: File,
pcid_from_client: File,
}
pub(crate) fn send<W: Write, T: Serialize>(w: &mut W, message: &T) -> Result<()> {
let mut data = Vec::new();
bincode::serialize_into(&mut data, message)?;
let length_bytes = u64::to_le_bytes(data.len() as u64);
w.write_all(&length_bytes)?;
w.write_all(&data)?;
Ok(())
}
pub(crate) fn recv<R: Read, T: DeserializeOwned>(r: &mut R) -> Result<T> {
let mut length_bytes = [0u8; 8];
r.read_exact(&mut length_bytes)?;
let length = u64::from_le_bytes(length_bytes);
if length > 0x100_000 {
panic!("pcid_interface: buffer too large");
}
let mut data = vec! [0u8; length as usize];
r.read_exact(&mut data)?;
Ok(bincode::deserialize_from(&data[..])?)
}
impl PcidServerHandle {
pub fn connect(pcid_to_client: RawFd, pcid_from_client: RawFd) -> Result<Self> {
Ok(Self {
pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client) },
pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client) },
})
}
pub fn connect_default() -> Result<Self> {
let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::<RawFd>().map_err(PcidClientHandleError::EnvValidityError)?;
let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::<RawFd>().map_err(PcidClientHandleError::EnvValidityError)?;
Self::connect(pcid_to_client_fd, pcid_from_client_fd)
}
pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> {
send(&mut self.pcid_from_client, req)
}
pub(crate) fn recv(&mut self) -> Result<PcidClientResponse> {
recv(&mut self.pcid_to_client)
}
pub fn fetch_config(&mut self) -> Result<SubdriverArguments> {
self.send(&PcidClientRequest::RequestConfig)?;
match self.recv()? {
PcidClientResponse::Config(a) => Ok(a),
other => Err(PcidClientHandleError::InvalidResponse(other)),
}
}
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
self.send(&PcidClientRequest::RequestFeatures)?;
match self.recv()? {
PcidClientResponse::AllFeatures(a) => Ok(a),
other => Err(PcidClientHandleError::InvalidResponse(other)),
}
}
pub fn feature_status(&mut self, feature: PciFeature) -> Result<FeatureStatus> {
self.send(&PcidClientRequest::FeatureStatus(feature))?;
match self.recv()? {
PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status),
other => Err(PcidClientHandleError::InvalidResponse(other)),
}
}
pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> {
self.send(&PcidClientRequest::EnableFeature(feature))?;
match self.recv()? {
PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()),
other => Err(PcidClientHandleError::InvalidResponse(other)),
}
}
pub fn feature_info(&mut self, feature: PciFeature) -> Result<PciFeatureInfo> {
self.send(&PcidClientRequest::FeatureInfo(feature))?;
match self.recv()? {
PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info),
other => Err(PcidClientHandleError::InvalidResponse(other)),
}
}
}
+7
View File
@@ -0,0 +1,7 @@
//! Interface to `pcid`.
#![feature(asm)]
mod driver_interface;
mod pci;
pub use driver_interface::*;
+232 -19
View File
@@ -1,37 +1,163 @@
#![feature(asm)]
#[macro_use] extern crate bitflags;
extern crate bitflags;
extern crate byteorder;
#[macro_use] extern crate serde_derive;
extern crate syscall;
extern crate toml;
use std::{env, i64};
use std::fs::{File, metadata, read_dir};
use std::io::Read;
use std::io::prelude::*;
use std::os::unix::io::{FromRawFd, RawFd};
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::{env, io, i64, thread};
use syscall::iopl;
use crate::config::Config;
use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType};
use crate::pci::{Pci, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType};
use crate::pci::cap::Capability as PciCapability;
mod config;
mod driver_interface;
mod pci;
fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
pub struct DriverHandler {
config: config::DriverConfig,
bus_num: u8,
dev_num: u8,
func_num: u8,
header: PciHeader,
capabilities: Vec<(u8, PciCapability)>,
state: Arc<State>,
}
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T {
let bus = PciBus {
pci,
num: bus_num,
};
let dev = PciDev {
bus: &bus,
num: dev_num,
};
let func = PciFunc {
dev: &dev,
num: func_num,
};
function(&func)
}
impl DriverHandler {
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(&self, function: F) -> T {
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function)
}
fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse {
use driver_interface::*;
use crate::pci::cap::{MsiCapability, MsixCapability};
match request {
PcidClientRequest::RequestConfig => {
PcidClientResponse::Config(args.clone())
}
PcidClientRequest::RequestFeatures => {
PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability {
PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))),
PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))),
_ => None,
}).collect())
}
PcidClientRequest::EnableFeature(feature) => match feature {
PciFeature::Msi => {
let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) {
Some(tuple) => tuple,
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
};
unsafe {
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
capability.set_enabled(true);
capability.write_message_control(func, offset);
});
}
PcidClientResponse::FeatureEnabled(feature)
}
PciFeature::MsiX => {
let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) {
Some(tuple) => tuple,
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
};
unsafe {
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
capability.set_msix_enabled(true);
capability.write_a(func, offset);
});
}
PcidClientResponse::FeatureEnabled(feature)
}
}
PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature {
PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability {
Some(FeatureStatus::enabled(msi.enabled()))
} else {
None
}).unwrap_or(FeatureStatus::Disabled),
PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability {
Some(FeatureStatus::enabled(msix.msix_enabled()))
} else {
None
}).unwrap_or(FeatureStatus::Disabled),
}),
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature {
PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) {
PciFeatureInfo::Msi(*info)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
}
PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) {
PciFeatureInfo::MsiX(*info)
} else {
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
}
}),
}
}
fn handle_spawn(mut self, pcid_to_client_write: Option<usize>, pcid_from_client_read: Option<usize>, args: driver_interface::SubdriverArguments) {
use driver_interface::*;
if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) {
let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) };
let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) };
while let Ok(msg) = recv(&mut pcid_from_client) {
let response = self.respond(msg, &args);
send(&mut pcid_to_client, &response).unwrap();
}
}
}
}
pub struct State {
threads: Mutex<Vec<thread::JoinHandle<()>>>,
pci: Pci,
}
fn handle_parsed_header(state: Arc<State>, config: &Config, bus_num: u8,
dev_num: u8, func_num: u8, header: PciHeader) {
let pci = &state.pci;
let raw_class: u8 = header.class().into();
let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}",
bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class,
header.subclass(), header.interface(), header.revision(), header.class());
match header.class() {
PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"),
PciClass::Storage => match header.subclass() {
0x01 => {
string.push_str(" IDE");
},
0x06 => {
string.push_str(" SATA");
0x06 => if header.interface() == 0 {
string.push_str(" SATA VND");
} else if header.interface() == 1 {
string.push_str(" SATA AHCI");
},
_ => ()
},
@@ -130,6 +256,8 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
pci.write(bus_num, dev_num, func_num, 0x3C, data);
}
let interrupt_pin = unsafe { pci.read(bus_num, dev_num, func_num, 0x3B) };
// Find BAR sizes
let mut bars = [PciBar::None; 6];
let mut bar_sizes = [0; 6];
@@ -166,9 +294,54 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
}
}
// TODO: find a better way to pass the header data down to the
// device driver, making passing the capabilities list etc
// posible.
let capabilities = {
let bus = PciBus {
pci,
num: bus_num,
};
let dev = PciDev {
bus: &bus,
num: dev_num
};
let func = PciFunc {
dev: &dev,
num: func_num,
};
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
};
println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
use driver_interface::LegacyInterruptPin;
let legacy_interrupt_pin = match interrupt_pin {
0 => None,
1 => Some(LegacyInterruptPin::IntA),
2 => Some(LegacyInterruptPin::IntB),
3 => Some(LegacyInterruptPin::IntC),
4 => Some(LegacyInterruptPin::IntD),
other => {
println!("pcid: invalid interrupt pin: {}", other);
None
}
};
let func = driver_interface::PciFunction {
bars,
bar_sizes,
bus_num,
dev_num,
func_num,
devid: header.device_id(),
legacy_interrupt_line: irq,
legacy_interrupt_pin,
venid: header.vendor_id(),
};
let subdriver_args = driver_interface::SubdriverArguments {
func,
};
let mut args = args.iter();
if let Some(program) = args.next() {
let mut command = Command::new(program);
@@ -199,11 +372,41 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8,
}
println!("PCID SPAWN {:?}", command);
match command.spawn() {
Ok(mut child) => match child.wait() {
Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()),
Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err)
},
let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() {
let mut fds1 = [0usize; 2];
let mut fds2 = [0usize; 2];
syscall::pipe2(&mut fds1, 0).expect("pcid: failed to create pcid->client pipe");
syscall::pipe2(&mut fds2, 0).expect("pcid: failed to create client->pcid pipe");
let [pcid_to_client_read, pcid_to_client_write] = fds1;
let [pcid_from_client_read, pcid_from_client_write] = fds2;
(Some(pcid_to_client_write), Some(pcid_from_client_read), vec! [("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write))])
} else {
(None, None, vec! [])
};
match command.envs(envs).spawn() {
Ok(mut child) => {
let driver_handler = DriverHandler {
bus_num,
dev_num,
func_num,
config: driver.clone(),
header,
state: Arc::clone(&state),
capabilities,
};
let thread = thread::spawn(move || {
driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args);
});
match child.wait() {
Ok(_status) => (),
Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err),
}
}
Err(err) => println!("pcid: failed to execute {:?}: {}", command, err)
}
}
@@ -241,18 +444,24 @@ fn main() {
}
}
let state = Arc::new(State {
pci: Pci::new(),
threads: Mutex::new(Vec::new()),
});
let pci = &state.pci;
unsafe { iopl(3).unwrap() };
print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n");
let pci = Pci::new();
'bus: for bus in pci.buses() {
'dev: for dev in bus.devs() {
for func in dev.funcs() {
let func_num = func.num;
match PciHeader::from_reader(func) {
Ok(header) => {
handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header);
handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header);
}
Err(PciHeaderError::NoDevice) => {
if func_num == 0 {
@@ -272,4 +481,8 @@ fn main() {
}
}
}
for thread in state.threads.lock().unwrap().drain(..) {
thread.join().unwrap();
}
}
+3 -1
View File
@@ -1,6 +1,8 @@
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq)]
use serde::{Serialize, Deserialize};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum PciBar {
None,
Memory(u32),
+3
View File
@@ -13,6 +13,9 @@ impl<'pci> PciBus<'pci> {
pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 {
self.pci.read(self.num, dev, func, offset)
}
pub unsafe fn write(&self, dev: u8, func: u8, offset: u8, value: u32) {
self.pci.write(self.num, dev, func, offset, value)
}
}
pub struct PciBusIter<'pci> {
+180
View File
@@ -0,0 +1,180 @@
use super::func::ConfigReader;
use serde::{Serialize, Deserialize};
pub struct CapabilityOffsetsIter<'a, R> {
offset: u8,
reader: &'a R,
}
impl<'a, R> CapabilityOffsetsIter<'a, R> {
pub fn new(offset: u8, reader: &'a R) -> Self {
Self {
offset,
reader,
}
}
}
impl<'a, R> Iterator for CapabilityOffsetsIter<'a, R>
where
R: ConfigReader
{
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
assert_eq!(self.offset & 0xF8, self.offset, "capability must be dword aligned");
if self.offset == 0 { return None };
let first_dword = dbg!(self.reader.read_u32(dbg!(self.offset)));
let next = ((first_dword >> 8) & 0xFF) as u8;
let offset = self.offset;
self.offset = next;
Some(offset)
}
}
}
#[repr(u8)]
pub enum CapabilityId {
Msi = 0x05,
MsiX = 0x11,
Pcie = 0x10,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum MsiCapability {
_32BitAddress {
message_control: u32,
message_address: u32,
message_data: u32,
},
_64BitAddress {
message_control: u32,
message_address_lo: u32,
message_address_hi: u32,
message_data: u32,
},
_32BitAddressWithPvm {
message_control: u32,
message_address: u32,
message_data: u32,
mask_bits: u32,
pending_bits: u32,
},
_64BitAddressWithPvm {
message_control: u32,
message_address_lo: u32,
message_address_hi: u32,
message_data: u32,
mask_bits: u32,
pending_bits: u32,
},
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PcieCapability {
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct MsixCapability {
pub a: u32,
pub b: u32,
pub c: u32,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Capability {
Msi(MsiCapability),
MsiX(MsixCapability),
Pcie(PcieCapability),
Other(u8),
}
impl Capability {
pub fn as_msi(&self) -> Option<&MsiCapability> {
match self {
&Self::Msi(ref msi) => Some(msi),
_ => None,
}
}
pub fn as_msix(&self) -> Option<&MsixCapability> {
match self {
&Self::MsiX(ref msix) => Some(msix),
_ => None,
}
}
pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> {
match self {
&mut Self::Msi(ref mut msi) => Some(msi),
_ => None,
}
}
pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> {
match self {
&mut Self::MsiX(ref mut msix) => Some(msix),
_ => None,
}
}
pub fn into_msi(self) -> Option<MsiCapability> {
match self {
Self::Msi(msi) => Some(msi),
_ => None,
}
}
pub fn into_msix(self) -> Option<MsixCapability> {
match self {
Self::MsiX(msix) => Some(msix),
_ => None,
}
}
unsafe fn parse_msi<R: ConfigReader>(reader: &R, offset: u8) -> Self {
Self::Msi(MsiCapability::parse(reader, offset))
}
unsafe fn parse_msix<R: ConfigReader>(reader: &R, offset: u8) -> Self {
Self::MsiX(MsixCapability {
a: reader.read_u32(offset),
b: reader.read_u32(offset + 4),
c: reader.read_u32(offset + 8),
})
}
unsafe fn parse_pcie<R: ConfigReader>(reader: &R, offset: u8) -> Self {
// TODO
Self::Pcie(PcieCapability {})
}
unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
assert_eq!(offset & 0xF8, offset, "capability must be dword aligned");
let dword = reader.read_u32(offset);
let capability_id = (dword & 0xFF) as u8;
if capability_id == CapabilityId::Msi as u8 {
Self::parse_msi(reader, offset)
} else if capability_id == CapabilityId::MsiX as u8 {
Self::parse_msix(reader, offset)
} else if capability_id == CapabilityId::Pcie as u8 {
Self::parse_pcie(reader, offset)
} else {
Self::Other(capability_id)
//panic!("unimplemented or malformed capability id: {}", capability_id)
}
}
}
pub struct CapabilitiesIter<'a, R> {
pub inner: CapabilityOffsetsIter<'a, R>,
}
impl<'a, R> Iterator for CapabilitiesIter<'a, R>
where
R: ConfigReader
{
type Item = (u8, Capability);
fn next(&mut self) -> Option<Self::Item> {
let offset = self.inner.next()?;
Some((offset, unsafe { Capability::parse(self.inner.reader, offset) }))
}
}
+3
View File
@@ -13,6 +13,9 @@ impl<'pci> PciDev<'pci> {
pub unsafe fn read(&self, func: u8, offset: u8) -> u32 {
self.bus.read(self.num, func, offset)
}
pub unsafe fn write(&self, func: u8, offset: u8, value: u32) {
self.bus.write(self.num, func, offset, value);
}
}
pub struct PciDevIter<'pci> {
+20 -1
View File
@@ -2,6 +2,9 @@ use byteorder::{LittleEndian, ByteOrder};
use super::PciDev;
// TODO: PCI Express Configuration Space, which uses a flat memory buffer, rather than IN/OUT
// instructions.
pub trait ConfigReader {
unsafe fn read_range(&self, offset: u8, len: u8) -> Vec<u8> {
assert!(len > 3 && len % 4 == 0);
@@ -17,11 +20,22 @@ pub trait ConfigReader {
}
unsafe fn read_u32(&self, offset: u8) -> u32;
unsafe fn read_u8(&self, offset: u8) -> u8 {
let dword_offset = (offset / 4) * 4;
let dword = self.read_u32(dword_offset);
let shift = (offset % 4) * 8;
((dword >> shift) & 0xFF) as u8
}
}
pub trait ConfigWriter {
unsafe fn write_u32(&self, offset: u8, value: u32);
}
pub struct PciFunc<'pci> {
pub dev: &'pci PciDev<'pci>,
pub num: u8
pub num: u8,
}
impl<'pci> ConfigReader for PciFunc<'pci> {
@@ -29,3 +43,8 @@ impl<'pci> ConfigReader for PciFunc<'pci> {
self.dev.read(self.num, offset)
}
}
impl<'pci> ConfigWriter for PciFunc<'pci> {
unsafe fn write_u32(&self, offset: u8, value: u32) {
self.dev.write(self.num, offset, value);
}
}
+7 -3
View File
@@ -3,6 +3,7 @@ use byteorder::{LittleEndian, ByteOrder};
use super::func::ConfigReader;
use super::class::PciClass;
use super::bar::PciBar;
use bitflags::bitflags;
#[derive(Debug, PartialEq)]
pub enum PciHeaderError {
@@ -26,7 +27,7 @@ bitflags! {
}
}
#[derive(Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PciHeader {
General {
vendor_id: u16,
@@ -123,7 +124,6 @@ impl PciHeader {
let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]);
let subsystem_id = LittleEndian::read_u16(&bytes[30..32]);
let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]);
// TODO: Parse out the capabilities list.
let cap_pointer = bytes[36];
let interrupt_line = bytes[44];
let interrupt_pin = bytes[45];
@@ -158,7 +158,6 @@ impl PciHeader {
let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]);
let io_base_upper = LittleEndian::read_u16(&bytes[32..34]);
let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]);
// TODO: Parse out the capabilities list.
let cap_pointer = bytes[36];
let expansion_rom = LittleEndian::read_u32(&bytes[40..44]);
let interrupt_line = bytes[44];
@@ -265,6 +264,11 @@ impl PciHeader {
}
}
pub fn cap_pointer(&self) -> u8 {
match self {
&PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer,
}
}
}
#[cfg(test)]
+23 -4
View File
@@ -1,3 +1,5 @@
use std::sync::Mutex;
pub use self::bar::PciBar;
pub use self::bus::{PciBus, PciBusIter};
pub use self::class::PciClass;
@@ -7,16 +9,22 @@ pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
mod bar;
mod bus;
pub mod cap;
mod class;
mod dev;
mod func;
pub mod header;
pub mod msi;
pub struct Pci;
pub struct Pci {
lock: Mutex<()>,
}
impl Pci {
pub fn new() -> Self {
Pci
Self {
lock: Mutex::new(()),
}
}
pub fn buses<'pci>(&'pci self) -> PciIter<'pci> {
@@ -24,7 +32,7 @@ impl Pci {
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
pub unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
let value: u32;
asm!("mov dx, 0xCF8
@@ -36,7 +44,13 @@ impl Pci {
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
let _guard = self.lock.lock().unwrap();
self.read_nolock(bus, dev, func, offset)
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
asm!("mov dx, 0xCF8
out dx, eax"
@@ -45,6 +59,11 @@ impl Pci {
out dx, eax"
: : "{eax}"(value) : "dx" : "intel", "volatile");
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
let _guard = self.lock.lock().unwrap();
self.write_nolock(bus, dev, func, offset, value)
}
}
pub struct PciIter<'pci> {
+351
View File
@@ -0,0 +1,351 @@
use std::fmt;
use super::bar::PciBar;
pub use super::cap::{MsiCapability, MsixCapability};
use super::func::{ConfigReader, ConfigWriter};
use syscall::{Io, Mmio};
impl MsiCapability {
pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8;
pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7;
pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E;
pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1;
pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070;
pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4;
pub const MC_MSI_ENABLED_BIT: u16 = 1;
pub unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
let dword = reader.read_u32(offset);
let message_control = (dword >> 16) as u16;
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
Self::_64BitAddressWithPvm {
message_control: dword,
message_address_lo: reader.read_u32(offset + 4),
message_address_hi: reader.read_u32(offset + 8),
message_data: reader.read_u32(offset + 12),
mask_bits: reader.read_u32(offset + 16),
pending_bits: reader.read_u32(offset + 20),
}
} else {
Self::_32BitAddressWithPvm {
message_control: dword,
message_address: reader.read_u32(offset + 4),
message_data: reader.read_u32(offset + 8),
mask_bits: reader.read_u32(offset + 12),
pending_bits: reader.read_u32(offset + 16),
}
}
} else {
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
Self::_64BitAddress {
message_control: dword,
message_address_lo: reader.read_u32(offset + 4),
message_address_hi: reader.read_u32(offset + 8),
message_data: reader.read_u32(offset + 12),
}
} else {
Self::_32BitAddress {
message_control: dword,
message_address: reader.read_u32(offset + 4),
message_data: reader.read_u32(offset + 8),
}
}
}
}
fn message_control_raw(&self) -> u32 {
match self {
Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control,
}
}
pub fn message_control(&self) -> u16 {
(self.message_control_raw() >> 16) as u16
}
pub fn set_message_control(&mut self, value: u16) {
let mut new_message_control = self.message_control_raw();
new_message_control &= 0x0000_FFFF;
new_message_control |= u32::from(value) << 16;
match self {
Self::_32BitAddress { ref mut message_control, .. }
| Self::_64BitAddress { ref mut message_control, .. }
| Self::_32BitAddressWithPvm { ref mut message_control, .. }
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
}
}
pub unsafe fn write_message_control<W: ConfigWriter>(&mut self, writer: &W, offset: u8) {
writer.write_u32(offset, self.message_control_raw());
}
pub fn is_pvt_capable(&self) -> bool {
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
}
pub fn has_64_bit_addr(&self) -> bool {
self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0
}
pub fn enabled(&self) -> bool {
self.message_control() & Self::MC_MSI_ENABLED_BIT != 0
}
pub fn set_enabled(&mut self, enabled: bool) {
let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT);
new_message_control |= u16::from(enabled);
self.set_message_control(new_message_control);
}
pub fn multi_message_capable(&self) -> u8 {
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
}
pub fn multi_message_enabled(&self) -> u8 {
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8
}
pub fn set_multi_message_enabled(&mut self, log_mme: u8) {
let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK);
new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT);
self.set_message_control(new_message_control);
}
}
impl MsixCapability {
pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15;
pub const MC_MSIX_ENABLED_SHIFT: u8 = 15;
pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14;
pub const MC_FUNCTION_MASK_SHIFT: u8 = 14;
pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF;
/// The Message Control field, containing the enabled and function mask bits, as well as the
/// table size.
pub const fn message_control(&self) -> u16 {
(self.a >> 16) as u16
}
pub fn set_message_control(&mut self, message_control: u16) {
self.a &= 0x0000_FFFF;
self.a |= u32::from(message_control) << 16;
}
/// Returns the MSI-X table size, subtracted by one.
pub const fn table_size_raw(&self) -> u16 {
self.message_control() & Self::MC_TABLE_SIZE_MASK
}
/// Returns the MSI-X table size.
pub const fn table_size(&self) -> u16 {
self.table_size_raw() + 1
}
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
/// MSI capability structure.
pub const fn msix_enabled(&self) -> bool {
self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0
}
/// The MSI-X function mask, which overrides each of the vectors' mask bit, when set.
pub const fn function_mask(&self) -> bool {
self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0
}
pub fn set_msix_enabled(&mut self, enabled: bool) {
let mut new_message_control = self.message_control();
new_message_control &= !(Self::MC_MSIX_ENABLED_BIT);
new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT;
self.set_message_control(new_message_control);
}
pub fn set_function_mask(&mut self, function_mask: bool) {
let mut new_message_control = self.message_control();
new_message_control &= !(Self::MC_FUNCTION_MASK_BIT);
new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT;
self.set_message_control(new_message_control);
}
pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8;
pub const TABLE_BIR_MASK: u32 = 0x0000_0007;
/// The table offset is guaranteed to be QWORD aligned (8 bytes).
pub const fn table_offset(&self) -> u32 {
self.b & Self::TABLE_OFFSET_MASK
}
/// The table BIR, which is used to map the offset to a memory location.
pub const fn table_bir(&self) -> u8 {
(self.b & Self::TABLE_BIR_MASK) as u8
}
pub fn set_table_offset(&mut self, offset: u32) {
assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned");
self.b &= !Self::TABLE_OFFSET_MASK;
self.b |= offset;
}
pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8;
pub const PBA_BIR_MASK: u32 = 0x0000_0007;
/// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes).
pub const fn pba_offset(&self) -> u32 {
self.c & Self::PBA_OFFSET_MASK
}
/// The Pending Bit Array BIR, which is used to map the offset to a memory location.
pub const fn pba_bir(&self) -> u8 {
(self.c & Self::PBA_BIR_MASK) as u8
}
pub fn set_pba_offset(&mut self, offset: u32) {
assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned");
self.c &= !Self::PBA_OFFSET_MASK;
self.c |= offset;
}
pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize {
if self.table_bir() > 5 {
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir());
}
let base = bars[usize::from(self.table_bir())];
if let PciBar::Memory(ptr) = base {
ptr as usize + self.table_offset() as usize
} else {
panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base);
}
}
pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize {
self.table_base_pointer(bars) + k as usize * 16
}
pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize {
if self.pba_bir() > 5 {
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir());
}
let base = bars[usize::from(self.pba_bir())];
if let PciBar::Memory(ptr) = base {
ptr as usize + self.pba_offset() as usize
} else {
panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base);
}
}
pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize {
self.pba_base_pointer(bars) + (k as usize / 32) * 4
}
pub const fn pba_bit_dword(&self, k: u16) -> u8 {
(k % 32) as u8
}
pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize {
self.pba_base_pointer(bars) + (k as usize / 64) * 8
}
pub const fn pba_bit_qword(&self, k: u16) -> u8 {
(k % 64) as u8
}
/// Write the first DWORD into configuration space (containing the partially modifiable Message
/// Control field).
pub unsafe fn write_a<W: ConfigWriter>(&self, writer: &W, offset: u8) {
writer.write_u32(offset, self.a)
}
/// Write the second DWORD into configuration space (containing the modifiable table
/// offset and the readonly table BIR).
pub unsafe fn write_b<W: ConfigWriter>(&self, writer: &W, offset: u8) {
writer.write_u32(offset + 4, self.a)
}
/// Write the third DWORD into configuration space (containing the modifiable pending bit array
/// offset, and the readonly PBA BIR).
pub unsafe fn write_c<W: ConfigWriter>(&self, writer: &W, offset: u8) {
writer.write_u32(offset + 8, self.a)
}
/// Write this capability structure back to configuration space.
pub unsafe fn write_all<W: ConfigWriter>(&self, writer: &W, offset: u8) {
self.write_a(writer, offset);
self.write_b(writer, offset);
self.write_c(writer, offset);
}
}
#[repr(packed)]
pub struct MsixTableEntry {
pub addr_lo: Mmio<u32>,
pub addr_hi: Mmio<u32>,
pub msg_data: Mmio<u32>,
pub vec_ctl: Mmio<u32>,
}
#[cfg(target_arch = "x86_64")]
pub mod x86_64 {
#[repr(u8)]
pub enum TriggerMode {
Edge = 0,
Level = 1,
}
#[repr(u8)]
pub enum LevelTriggerMode {
Deassert = 0,
Assert = 1,
}
#[repr(u8)]
pub enum DeliveryMode {
Fixed = 0b000,
LowestPriority = 0b001,
Smi = 0b010,
// 0b011 is reserved
Nmi = 0b100,
Init = 0b101,
// 0b110 is reserved
ExtInit = 0b111,
}
// TODO: should the reserved field be preserved?
pub const fn message_address(destination_id: u8, rh: bool, dm: bool, xx: u8) -> u32 {
0xFEE0_0000u32
| ((destination_id as u32) << 12)
| ((rh as u32) << 3)
| ((dm as u32) << 2)
| xx as u32
}
pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 {
((trigger_mode as u32) << 15)
| ((level_trigger_mode as u32) << 14)
| ((delivery_mode as u32) << 8)
| vector as u32
}
pub const fn message_data_level_triggered(level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 {
message_data(TriggerMode::Level, level_trigger_mode, delivery_mode, vector)
}
pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 {
message_data(TriggerMode::Edge, LevelTriggerMode::Deassert, delivery_mode, vector)
}
}
impl MsixTableEntry {
pub fn addr_lo(&self) -> u32 {
self.addr_lo.read()
}
pub fn addr_hi(&self) -> u32 {
self.addr_hi.read()
}
pub fn msg_data(&self) -> u32 {
self.msg_data.read()
}
pub fn vec_ctl(&self) -> u32 {
self.vec_ctl.read()
}
pub fn addr(&self) -> u64 {
u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32)
}
pub const VEC_CTL_MASK_BIT: u32 = 1;
pub fn mask(&mut self) {
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true)
}
pub fn unmask(&mut self) {
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false)
}
}
impl fmt::Debug for MsixTableEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("MsixTableEntry")
.field("addr", &self.addr())
.field("msg_data", &self.msg_data())
.field("vec_ctl", &self.vec_ctl())
.finish()
}
}
+6 -1
View File
@@ -13,13 +13,18 @@ path = "src/lib.rs"
[dependencies]
bitflags = "1"
chashmap = { git = "https://gitlab.redox-os.org/redox-os/chashmap.git" }
crossbeam-channel = "0.4"
futures = "0.3"
plain = "0.2"
lazy_static = "1.4"
spin = "0.4"
log = "0.4"
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" }
redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" }
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
smallvec = { version = "1", features = ["serde"] }
thiserror = "1"
toml = "0.5"
pcid = { path = "../pcid" }
+1 -1
View File
@@ -14,7 +14,7 @@ use thiserror::Error;
pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK};
#[derive(Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ConfigureEndpointsReq {
/// Index into the configuration descriptors of the device descriptor.
pub config_desc: u8,
+242 -104
View File
@@ -1,140 +1,278 @@
#[macro_use]
extern crate bitflags;
extern crate event;
extern crate plain;
extern crate syscall;
use std::convert::TryInto;
use std::fs::{self, File};
use std::future::Future;
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::{Arc, Mutex};
use std::env;
use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo};
use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry};
use event::{Event, EventQueue};
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Result, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::sync::Arc;
use std::{env, io};
use log::info;
use syscall::data::Packet;
use syscall::error::EWOULDBLOCK;
use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE};
use syscall::scheme::SchemeMut;
use syscall::scheme::Scheme;
use syscall::io::Io;
use crate::xhci::Xhci;
use crate::xhci::{InterruptMethod, Xhci};
// Declare as pub so that no warnings appear due to parts of the interface code not being used by
// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't
// mean anything.
pub mod driver_interface;
mod driver_interface;
mod usb;
mod xhci;
/// Read the local APIC id of the bootstrap processor.
fn read_bsp_apic_id() -> io::Result<u32> {
let mut buffer = [0u8; 8];
let mut file = File::open("irq:bsp")?;
let bytes_read = file.read(&mut buffer)?;
Ok(if bytes_read == 8 {
u64::from_le_bytes(buffer) as u32
} else if bytes_read == 4 {
u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]])
} else {
panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::<usize>());
})
}
/// Allocate an interrupt vector, located at the BSP's IDT.
fn allocate_interrupt_vector() -> io::Result<Option<(u8, File)>> {
let available_irqs = fs::read_dir("irq:")?;
for entry in available_irqs {
let entry = entry?;
let path = entry.path();
let file_name = match path.file_name() {
Some(f) => f,
None => continue,
};
let path_str = match file_name.to_str() {
Some(s) => s,
None => continue,
};
if let Ok(irq_number) = path_str.parse::<u8>() {
// if found, reserve the irq
let irq_handle = File::create(format!("irq:{}", irq_number))?;
let interrupt_vector = irq_number + 32;
return Ok(Some((interrupt_vector, irq_handle)));
}
}
Ok(None)
}
async fn handle_packet(hci: Arc<Xhci>, packet: Packet) -> Packet {
todo!()
}
fn main() {
let mut args = env::args().skip(1);
let mut name = args.next().expect("xhcid: no name provided");
name.push_str("_xhci");
let bar_str = args.next().expect("xhcid: no address provided");
let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address");
// Daemonize
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 {
return;
}
let irq_str = args.next().expect("xhcid: no IRQ provided");
let irq = irq_str.parse::<u8>().expect("xhcid: failed to parse irq");
match redox_log::RedoxLogger::new("usb", "host", "xhci.log") {
Ok(logger) => match logger.with_stdout_mirror().enable() {
Ok(_) => {
println!("xhcid: enabled logger");
log::set_max_level(log::LevelFilter::Debug);
}
Err(error) => eprintln!("xhcid: failed to set default logger: {}", error),
}
Err(error) => eprintln!("xhcid: failed to initialize logger: {}", error),
}
let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid");
let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config");
info!("XHCI PCI CONFIG: {:?}", pci_config);
let bar = pci_config.func.bars[0];
let irq = pci_config.func.legacy_interrupt_line;
let bar_ptr = match bar {
pcid_interface::PciBar::Memory(ptr) => ptr,
other => panic!("Expected memory bar, found {}", other),
};
let address = unsafe {
syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
.expect("xhcid: failed to map address")
};
let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features");
info!("XHCI PCI FEATURES: {:?}", all_pci_features);
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
dbg!(has_msi, msi_enabled);
dbg!(has_msix, msix_enabled);
if has_msi && !msi_enabled && !has_msix {
pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI");
info!("Enabled MSI");
msi_enabled = true;
}
if has_msix && !msix_enabled {
pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X");
info!("Enabled MSI-X");
msix_enabled = true;
}
let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled {
let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") {
PciFeatureInfo::Msi(s) => s,
PciFeatureInfo::MsiX(_) => panic!(),
};
// use one vector
capability.set_multi_message_enabled(0);
todo!("msi (msix is implemented though)")
} else if msix_enabled {
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") {
PciFeatureInfo::Msi(_) => panic!(),
PciFeatureInfo::MsiX(s) => s,
};
let table_size = capability.table_size();
let table_base = capability.table_base_pointer(pci_config.func.bars);
let table_min_length = table_size * 16;
let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8);
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
dbg!(table_size, table_base, table_min_length, pba_base);
if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) {
todo!()
}
if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) {
todo!()
}
let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry;
let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64;
let mut info = xhci::MsixInfo {
virt_table_base: NonNull::new(virt_table_base).unwrap(),
virt_pba_base: NonNull::new(virt_pba_base).unwrap(),
capability,
};
// Allocate one msi vector.
{
use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix};
// primary interrupter
let k = 0;
assert_eq!(std::mem::size_of::<MsixTableEntry>(), 16);
let table_entry_pointer = info.table_entry_pointer(k);
let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id");
let rh = false;
let dm = false;
let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00);
let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left");
let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector);
table_entry_pointer.addr_lo.write(addr);
table_entry_pointer.addr_hi.write(0);
table_entry_pointer.msg_data.write(msg_data);
table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false);
(Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info)))
}
} else if pci_config.func.legacy_interrupt_pin.is_some() {
// legacy INTx# interrupt pins.
(Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx)
} else {
// no interrupts at all
(None, InterruptMethod::Polling)
};
std::thread::sleep(std::time::Duration::from_millis(300));
print!(
"{}",
format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)
format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq)
);
// Daemonize
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 {
let socket_fd = syscall::open(
format!(":usb/{}", name),
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
)
.expect("xhcid: failed to create usb scheme");
let socket = Arc::new(RefCell::new(unsafe {
File::from_raw_fd(socket_fd as RawFd)
}));
let socket_fd = syscall::open(
format!(":usb/{}", name),
syscall::O_RDWR | syscall::O_CREAT,
)
.expect("xhcid: failed to create usb scheme");
let socket = Arc::new(Mutex::new(unsafe {
File::from_raw_fd(socket_fd as RawFd)
}));
let mut irq_file =
File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device"));
xhci::start_irq_reactor(&hci, irq_file);
futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe");
let address = unsafe {
syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
.expect("xhcid: failed to map address")
};
{
let hci = Arc::new(RefCell::new(
Xhci::new(name, address).expect("xhcid: failed to allocate device"),
));
let mut event_queue =
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
hci.borrow_mut().probe().expect("xhcid: failed to probe");
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
let mut event_queue =
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
let todo = Arc::new(Mutex::new(Vec::<Packet>::new()));
let todo_futures = Arc::new(Mutex::new(Vec::<Pin<Box<dyn Future<Output = usize> + Send + Sync + 'static>>>::new()));
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
let socket_fd = socket.lock().unwrap().as_raw_fd();
let socket_packet = socket.clone();
event_queue
.add(socket_fd, move |_| -> io::Result<Option<()>> {
let mut socket = socket_packet.lock().unwrap();
let mut todo = todo.lock().unwrap();
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
loop {
let mut packet = Packet::default();
match socket.read(&mut packet) {
Ok(0) => break,
Ok(_) => (),
Err(err) => return Err(err),
}
let hci_irq = hci.clone();
let socket_irq = socket.clone();
let todo_irq = todo.clone();
event_queue
.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
let mut irq = [0; 8];
irq_file.read(&mut irq)?;
let a = packet.a;
hci.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.push(packet);
} else {
socket.write(&packet)?;
}
}
Ok(None)
})
.expect("xhcid: failed to catch events on scheme file");
if hci_irq.borrow_mut().trigger_irq() {
irq_file.write(&mut irq)?;
event_queue
.trigger_all(Event { fd: 0, flags: 0 })
.expect("xhcid: failed to trigger events");
let mut todo = todo_irq.borrow_mut();
let mut i = 0;
while i < todo.len() {
let a = todo[i].a;
hci_irq.borrow_mut().handle(&mut todo[i]);
if todo[i].a == (-EWOULDBLOCK) as usize {
todo[i].a = a;
i += 1;
} else {
socket_irq.borrow_mut().write(&mut todo[i])?;
todo.remove(i);
}
}
}
event_queue.run().expect("xhcid: failed to handle events");
Ok(None)
})
.expect("xhcid: failed to catch events on IRQ file");
let socket_fd = socket.borrow().as_raw_fd();
let socket_packet = socket.clone();
event_queue
.add(socket_fd, move |_| -> Result<Option<()>> {
loop {
let mut packet = Packet::default();
match socket_packet.borrow_mut().read(&mut packet) {
Ok(0) => break,
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
Ok(_) => (),
Err(err) => return Err(err),
}
let a = packet.a;
hci.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
Ok(None)
})
.expect("xhcid: failed to catch events on scheme file");
event_queue
.trigger_all(Event { fd: 0, flags: 0 })
.expect("xhcid: failed to trigger events");
event_queue.run().expect("xhcid: failed to handle events");
}
unsafe {
let _ = syscall::physunmap(address);
}
unsafe {
let _ = syscall::physunmap(address);
}
}
+20
View File
@@ -27,6 +27,13 @@ pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24;
pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF;
pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0;
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000;
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27;
pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT;
pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26;
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000;
pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21;
impl CapabilityRegs {
pub fn lec(&self) -> bool {
self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT)
@@ -48,4 +55,17 @@ impl CapabilityRegs {
pub fn ext_caps_ptr_in_dwords(&self) -> u16 {
((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16
}
pub fn max_scratchpad_bufs_lo(&self) -> u8 {
((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8
}
pub fn spr(&self) -> bool {
self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT)
}
pub fn max_scratchpad_bufs_hi(&self) -> u8 {
((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8
}
pub fn max_scratchpad_bufs(&self) -> u16 {
u16::from(self.max_scratchpad_bufs_lo())
| (u16::from(self.max_scratchpad_bufs_hi()) << 5)
}
}
-45
View File
@@ -1,45 +0,0 @@
use syscall::error::Result;
use super::event::EventRing;
use super::ring::Ring;
use super::trb::Trb;
pub struct CommandRing {
pub ring: Ring,
pub events: EventRing,
}
impl CommandRing {
pub fn new() -> Result<CommandRing> {
Ok(CommandRing {
ring: Ring::new(16, true)?,
events: EventRing::new()?,
})
}
pub fn crcr(&self) -> u64 {
self.ring.register()
}
pub fn erdp(&self) -> u64 {
self.events.ring.register()
}
pub fn erstba(&self) -> u64 {
self.events.ste.physical() as u64
}
pub fn next(&mut self) -> (&mut Trb, bool, &mut Trb) {
let cmd = self.ring.next();
let event = self.events.next();
(cmd.0, cmd.1, event)
}
pub fn next_cmd(&mut self) -> (&mut Trb, bool) {
self.ring.next()
}
pub fn next_event(&mut self) -> &mut Trb {
self.events.next()
}
}
+40 -4
View File
@@ -1,5 +1,6 @@
use std::collections::BTreeMap;
use log::debug;
use syscall::error::Result;
use syscall::io::{Dma, Io, Mmio};
@@ -59,7 +60,7 @@ pub struct InputContext {
}
impl InputContext {
pub fn dump_control(&self) {
println!(
debug!(
"INPUT CONTEXT: {} {} [{} {} {} {} {}] {}",
self.drop_context.read(),
self.add_context.read(),
@@ -75,7 +76,7 @@ impl InputContext {
pub struct DeviceContextList {
pub dcbaa: Dma<[u64; 256]>,
pub contexts: Vec<Dma<DeviceContext>>,
pub contexts: Box<[Dma<DeviceContext>]>,
}
impl DeviceContextList {
@@ -91,8 +92,8 @@ impl DeviceContextList {
}
Ok(DeviceContextList {
dcbaa: dcbaa,
contexts: contexts,
dcbaa,
contexts: contexts.into_boxed_slice(),
})
}
@@ -159,3 +160,38 @@ impl StreamContextArray {
self.contexts.physical() as u64
}
}
#[repr(packed)]
pub struct ScratchpadBufferEntry {
pub value: Mmio<u64>,
}
impl ScratchpadBufferEntry {
pub fn set_addr(&mut self, addr: u64) {
self.value.write(addr);
}
}
pub struct ScratchpadBufferArray {
pub entries: Dma<[ScratchpadBufferEntry]>,
pub pages: Vec<usize>,
}
impl ScratchpadBufferArray {
pub fn new(page_size: usize, entries: u16) -> Result<Self> {
let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? };
let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<usize> {
let pointer = unsafe { syscall::physalloc(page_size)? };
assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned");
entry.set_addr(pointer as u64);
Ok(pointer)
}).collect::<Result<Vec<usize>, _>>()?;
Ok(Self {
entries,
pages,
})
}
pub fn register(&self) -> usize {
self.entries.physical()
}
}
+7
View File
@@ -12,6 +12,7 @@ pub struct EventRingSte {
_rsvd2: Mmio<u32>,
}
// TODO: Use atomic operations, and perhaps an occasional lock for reallocating.
pub struct EventRing {
pub ste: Dma<[EventRingSte]>,
pub ring: Ring,
@@ -33,4 +34,10 @@ impl EventRing {
pub fn next(&mut self) -> &mut Trb {
self.ring.next().0
}
pub fn erdp(&self) -> u64 {
self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0
}
pub fn erstba(&self) -> u64 {
self.ste.physical() as u64
}
}
+468
View File
@@ -0,0 +1,468 @@
use std::collections::BTreeMap;
use std::fs::File;
use std::future::Future;
use std::io::prelude::*;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{self, AtomicUsize};
use std::{io, mem, task, thread};
use std::os::unix::io::AsRawFd;
use crossbeam_channel::{Sender, Receiver};
use log::{debug, error, info, warn, trace};
use futures::Stream;
use syscall::Io;
use event::{Event, EventQueue};
use super::Xhci;
use super::ring::Ring;
use super::trb::{Trb, TrbCompletionCode, TrbType};
use super::event::EventRing;
/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back
/// by the future unless it completed).
#[derive(Debug)]
pub struct State {
waker: task::Waker,
kind: StateKind,
message: Arc<Mutex<Option<NextEventTrb>>>,
is_isoch_or_vf: bool,
}
#[derive(Debug)]
pub struct NextEventTrb {
pub event_trb: Trb,
pub src_trb: Option<Trb>,
}
// TODO: Perhaps all of the transfer rings used by the xHC should be stored linearly, and then
// indexed using this struct instead.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct RingId {
pub port: u8,
pub endpoint_num: u8,
pub stream_id: u16,
}
impl RingId {
pub const fn default_control_pipe(port: u8) -> Self {
Self {
port,
endpoint_num: 0,
stream_id: 0,
}
}
}
/// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for
/// example the Command Completion Event and the Transfer Event TDs, they have to be
/// distinguishable. Luckily, the xHC also gives us the actual (physical) pointer to the source
/// TRB, from the command ring, unless the event TD has one the completion codes Ring Underrun,
/// Ring Overrun, or VF Event Ring Full Error. When these errors are encountered, it simply
/// indicates that the commands causing the errors continue to be pending, and thus no information
/// is lost.
#[derive(Clone, Copy, Debug)]
pub enum StateKind {
CommandCompletion { phys_ptr: u64 },
Transfer { phys_ptr: u64, ring_id: RingId },
Other(TrbType),
}
impl StateKind {
pub fn trb_type(&self) -> TrbType {
match self {
&Self::CommandCompletion { .. } => TrbType::CommandCompletion,
&Self::Transfer { .. } => TrbType::Transfer,
&Self::Other(ty) => ty,
}
}
}
pub struct IrqReactor {
hci: Arc<Xhci>,
irq_file: Option<File>,
receiver: Receiver<NewPendingTrb>,
states: Vec<State>,
// TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps
// the event ring should be owned here?
}
pub type NewPendingTrb = State;
impl IrqReactor {
pub fn new(hci: Arc<Xhci>, receiver: Receiver<NewPendingTrb>, irq_file: Option<File>) -> Self {
Self {
hci,
irq_file,
receiver,
states: Vec::new(),
}
}
// TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling).
fn pause(&self) {
std::thread::yield_now();
}
fn run_polling(mut self) {
debug!("Running IRQ reactor in polling mode.");
let hci_clone = Arc::clone(&self.hci);
'event_loop: loop {
let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap();
let index = event_ring_guard.ring.next_index();
let mut trb;
'busy_waiting: loop {
trb = &event_ring_guard.ring.trbs[index];
if trb.completion_code() == TrbCompletionCode::Invalid as u8 {
self.pause();
continue 'busy_waiting;
}
}
if self.check_event_ring_full(trb.clone()) { continue 'event_loop }
self.handle_requests();
self.acknowledge(trb.clone());
self.update_erdp(&*event_ring_guard);
}
}
fn run_with_irq_file(mut self) {
debug!("Running IRQ reactor with IRQ file and event queue");
let hci_clone = Arc::clone(&self.hci);
let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue");
let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd();
let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() };
event_queue.add(irq_fd, move |_| -> io::Result<Option<()>> {
trace!("IRQ event queue notified");
let mut buffer = [0u8; 8];
let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme");
if !self.hci.received_irq() {
// continue only when an IRQ to this device was received
trace!("no interrupt pending");
return Ok(None);
}
trace!("IRQ reactor received an IRQ");
let _ = self.irq_file.as_mut().unwrap().write(&buffer);
// TODO: More event rings, probably even with different IRQs.
let mut event_ring = hci_clone.primary_event_ring.lock().unwrap();
let mut count = 0;
'trb_loop: loop {
let event_trb = &mut event_ring.ring.trbs[event_trb_index];
if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 {
if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") }
// no more events were found, continue the loop
return Ok(None);
} else { count += 1 }
trace!("Found event TRB: {:?}", event_trb);
if self.check_event_ring_full(event_trb.clone()) {
info!("Had to resize event TRB, retrying...");
hci_clone.event_handler_finished();
return Ok(None);
}
self.handle_requests();
self.acknowledge(event_trb.clone());
event_trb.reserved(false);
self.update_erdp(&*event_ring);
event_trb_index = event_ring.ring.next_index();
}
}).expect("xhcid: failed to catch irq events");
event_queue.run().expect("xhcid: failed to run IRQ event queue");
}
fn update_erdp(&self, event_ring: &EventRing) {
let dequeue_pointer_and_dcs = event_ring.erdp();
let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE;
assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring");
debug!("Updated ERDP to {:#0x}", dequeue_pointer);
self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer);
}
fn handle_requests(&mut self) {
self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req)));
}
fn acknowledge(&mut self, trb: Trb) {
let mut index = 0;
loop {
if index >= self.states.len() { break }
match self.states[index].kind {
StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) {
trace!("Found matching command completion future");
let state = self.states.remove(index);
// Before waking, it's crucial that the command TRB that generated this event
// is fetched before removing this event TRB from the queue.
let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) {
Some(command_trb) => {
let t = command_trb.clone();
command_trb.reserved(false);
t
},
None => {
warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb);
continue;
}
};
// TODO: Validate the command TRB.
*state.message.lock().unwrap() = Some(NextEventTrb {
src_trb: Some(command_trb.clone()),
event_trb: trb.clone(),
});
trace!("Waking up future with waker: {:?}", state.waker);
state.waker.wake();
return;
} else if trb.completion_trb_pointer().is_none() {
warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb);
continue;
} else {
// The event TRB simply didn't match the current future
continue;
}
StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() {
if trb.transfer_event_trb_pointer() == Some(phys_ptr) {
// Give the source transfer TRB together with the event TRB, to the future.
let state = self.states.remove(index);
*state.message.lock().unwrap() = Some(NextEventTrb {
src_trb: Some(src_trb),
event_trb: trb.clone(),
});
state.waker.wake();
return;
} else if trb.transfer_event_trb_pointer().is_none() {
// Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full.
//
// These errors are caused when either an isoch transfer that shall write data, doesn't
// have any data since the ring is empty, or if an isoch receive is impossible due to a
// full ring. The Virtual Function Event Ring Full is only for Virtual Machine
// Managers, and since this isn't implemented yet, they are irrelevant.
//
// The best solution here is to differentiate between isoch transfers (and
// virtual function event rings when virtualization gets implemented), with
// regular commands and transfers, and send the error TRB to all of them, or
// possibly an error code wrapped in a Result.
self.acknowledge_failed_transfer_trbs(trb);
return;
} else {
// The event TRB simply didn't match the current future
continue;
}
} else { continue }
StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => {
let state = self.states.remove(index);
state.waker.wake();
return;
}
_ => {
index += 1;
continue;
}
}
}
warn!("Lost event TRB: {:?}", trb);
}
fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) {
let mut index = 0;
loop {
if ! self.states[index].is_isoch_or_vf {
index += 1;
if index >= self.states.len() {
break;
}
continue;
}
let state = self.states.remove(index);
*state.message.lock().unwrap() = Some(NextEventTrb {
event_trb: trb.clone(),
src_trb: None,
});
state.waker.wake();
}
}
/// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring
/// Full. If so, it grows the event ring. The return value is whether the event ring was full,
/// and then grown.
fn check_event_ring_full(&mut self, event_trb: Trb) -> bool {
let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8;
if had_event_ring_full_error {
self.grow_event_ring();
}
had_event_ring_full_error
}
/// Grows the event ring
fn grow_event_ring(&mut self) {
// TODO
error!("TODO: grow event ring");
}
pub fn run(mut self) {
if self.irq_file.is_some() {
self.run_with_irq_file();
} else {
self.run_polling();
}
}
}
struct FutureState {
message: Arc<Mutex<Option<NextEventTrb>>>,
is_isoch_or_vf: bool,
state_kind: StateKind,
}
enum EventTrbFuture {
Pending { state: FutureState, sender: Sender<State>, },
Finished,
}
impl Future for EventTrbFuture {
type Output = NextEventTrb;
fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
let this = self.get_mut();
let message = match this {
&mut Self::Pending { ref state, ref sender } => match state.message.lock().unwrap().take() {
Some(message) => message,
None => {
sender.send(State {
message: Arc::clone(&state.message),
is_isoch_or_vf: state.is_isoch_or_vf,
kind: state.state_kind,
waker: context.waker().clone(),
}).expect("IRQ reactor thread unexpectedly stopped");
return task::Poll::Pending;
}
}
&mut Self::Finished => panic!("Polling finished EventTrbFuture again."),
};
*this = Self::Finished;
task::Poll::Ready(message)
}
}
impl Xhci {
pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option<Trb> {
self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten()
}
pub fn with_ring<T, F: FnOnce(&Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
use super::RingOrStreams;
let slot_state = self.port_states.get(&(id.port as usize))?;
let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?;
let ring_ref = match endpoint_state.transfer {
RingOrStreams::Ring(ref ring) => ring,
RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?,
};
Some(function(ring_ref))
}
pub fn with_ring_mut<T, F: FnOnce(&mut Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
use super::RingOrStreams;
let mut slot_state = self.port_states.get_mut(&(id.port as usize))?;
let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?;
let ring_ref = match endpoint_state.transfer {
RingOrStreams::Ring(ref mut ring) => ring,
RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?,
};
Some(function(ring_ref))
}
pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
if ! trb.is_transfer_trb() {
panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb)
}
let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8;
EventTrbFuture::Pending {
state: FutureState {
is_isoch_or_vf,
state_kind: StateKind::Transfer {
ring_id,
phys_ptr: ring.trb_phys_ptr(trb),
},
message: Arc::new(Mutex::new(None)),
},
sender: self.irq_reactor_sender.clone(),
}
}
pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
if ! trb.is_command_trb() {
panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb)
}
dbg!(command_ring.trbs.physical());
EventTrbFuture::Pending {
state: FutureState {
// This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization).
is_isoch_or_vf: false,
state_kind: StateKind::CommandCompletion {
phys_ptr: command_ring.trb_phys_ptr(trb),
},
message: Arc::new(Mutex::new(None)),
},
sender: self.irq_reactor_sender.clone(),
}
}
pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future<Output = NextEventTrb> + Send + Sync + 'static {
let valid_trb_types = [
TrbType::PortStatusChange as u8,
TrbType::BandwidthRequest as u8,
TrbType::Doorbell as u8,
TrbType::HostController as u8,
TrbType::DeviceNotification as u8,
TrbType::MfindexWrap as u8,
];
if ! valid_trb_types.contains(&(trb_type as u8)) {
panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type)
}
EventTrbFuture::Pending {
state: FutureState {
is_isoch_or_vf: false,
state_kind: StateKind::Other(trb_type),
message: Arc::new(Mutex::new(None)),
},
sender: self.irq_reactor_sender.clone(),
}
}
}
+363 -228
View File
@@ -1,107 +1,156 @@
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fs::File;
use std::future::Future;
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak};
use std::{mem, process, slice, sync::atomic, task};
use std::sync::{Arc, Mutex, MutexGuard, Weak};
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::{mem, process, slice, sync::atomic, task, thread};
use chashmap::CHashMap;
use crossbeam_channel::{Receiver, Sender};
use log::{debug, error, info, trace, warn};
use serde::Deserialize;
use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT};
use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO};
use syscall::flag::O_RDONLY;
use syscall::io::{Dma, Io};
use crate::usb;
use pcid_interface::msi::{MsixTableEntry, MsixCapability};
use pcid_interface::{PcidServerHandle, PciFeature};
mod capability;
mod command;
mod context;
mod doorbell;
mod event;
mod extended;
pub mod irq_reactor;
mod operational;
mod port;
mod ring;
mod runtime;
mod scheme;
pub mod scheme;
mod trb;
use self::capability::CapabilityRegs;
use self::command::CommandRing;
use self::context::{DeviceContextList, InputContext, StreamContextArray};
use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray};
use self::doorbell::Doorbell;
use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId};
use self::event::EventRing;
use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap};
use self::operational::OperationalRegs;
use self::port::Port;
use self::ring::Ring;
use self::runtime::{Interrupter, RuntimeRegs};
use self::trb::{TransferKind, TrbCompletionCode, TrbType};
use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType};
use self::scheme::EndpIfState;
use crate::driver_interface::*;
struct Device<'a> {
ring: &'a mut Ring,
cmd: &'a mut CommandRing,
db: &'a mut Doorbell,
int: &'a mut Interrupter,
pub enum InterruptMethod {
/// No interrupts whatsoever; the driver will instead rely on polling event rings.
Polling,
/// Legacy PCI INTx# interrupt pin.
Intx,
/// Message signaled interrupts.
Msi,
/// Extended message signaled interrupts.
MsiX(Mutex<MsixInfo>),
}
impl<'a> Device<'a> {
fn get_desc<T>(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) {
pub struct MsixInfo {
pub virt_table_base: NonNull<MsixTableEntry>,
pub virt_pba_base: NonNull<u64>,
pub capability: MsixCapability,
}
impl MsixInfo {
pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry {
&mut *self.virt_table_base.as_ptr().offset(k as isize)
}
pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry {
assert!(k < self.capability.table_size() as usize);
unsafe { self.table_entry_pointer_unchecked(k) }
}
pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 {
&mut *self.virt_pba_base.as_ptr().offset(k as isize)
}
pub fn pba_pointer(&mut self, k: usize) -> &mut u64 {
assert!(k < self.capability.table_size() as usize);
unsafe { self.pba_pointer_unchecked(k) }
}
pub fn pba(&mut self, k: usize) -> bool {
let byte = k / 64;
let bit = k % 64;
*self.pba_pointer(byte) & (1 << bit) != 0
}
}
impl Xhci {
/// Gets descriptors, before the port state is initiated.
async fn get_desc_raw<T>(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma<T>) -> Result<()> {
let len = mem::size_of::<T>();
{
let (cmd, cycle) = self.ring.next();
let future = {
let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?;
let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe");
let (cmd, cycle) = ring.next();
cmd.setup(
usb::Setup::get_descriptor(kind, index, 0, len as u16),
TransferKind::In,
cycle,
);
}
{
let (cmd, cycle) = self.ring.next();
let (cmd, cycle) = ring.next();
cmd.data(desc.physical(), len as u16, true, cycle);
}
{
let (cmd, cycle) = self.ring.next();
cmd.status(false, cycle);
}
let last_index = ring.next_index();
let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle);
cmd.status(0, true, true, false, false, cycle);
self.db.write(1);
self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index])
};
{
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
}
self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell());
self.int.erdp.write(self.cmd.erdp());
let trbs = future.await;
let event_trb = trbs.event_trb;
let status_trb = trbs.src_trb.unwrap();
self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?;
self.event_handler_finished();
Ok(())
}
fn get_device(&mut self) -> Result<usb::DeviceDescriptor> {
async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result<usb::DeviceDescriptor> {
let mut desc = Dma::<usb::DeviceDescriptor>::zeroed()?;
self.get_desc(usb::DescriptorKind::Device, 0, &mut desc);
self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?;
Ok(*desc)
}
fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> {
async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> {
let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?;
self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc);
self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?;
Ok(*desc)
}
fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> {
async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> {
let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?;
self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc);
self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?;
Ok(*desc)
}
fn get_string(&mut self, index: u8) -> Result<String> {
async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result<String> {
let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?;
self.get_desc(usb::DescriptorKind::String, index, &mut sdesc);
self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?;
let len = sdesc.0 as usize;
if len > 2 {
@@ -113,38 +162,54 @@ impl<'a> Device<'a> {
}
pub struct Xhci {
cap: &'static mut CapabilityRegs,
op: &'static mut OperationalRegs,
ports: &'static mut [Port],
dbs: &'static mut [Doorbell],
run: &'static mut RuntimeRegs,
dev_ctx: DeviceContextList,
cmd: CommandRing,
// immutable
cap: &'static CapabilityRegs,
page_size: usize,
// XXX: It would be really useful to be able to mutably access individual elements of a slice,
// without having to wrap every element in a lock (which wouldn't work since they're packed).
op: Mutex<&'static mut OperationalRegs>,
ports: Mutex<&'static mut [Port]>,
dbs: Mutex<&'static mut [Doorbell]>,
run: Mutex<&'static mut RuntimeRegs>,
cmd: Mutex<Ring>,
primary_event_ring: Mutex<EventRing>,
// immutable
dev_ctx: DeviceContextList,
scratchpad_buf_arr: Option<ScratchpadBufferArray>,
// used for the extended capabilities, and so far none of them are mutated, and thus no lock.
base: *const u8,
handles: BTreeMap<usize, scheme::Handle>,
next_handle: usize,
port_states: BTreeMap<usize, PortState>,
handles: CHashMap<usize, scheme::Handle>,
next_handle: AtomicUsize,
port_states: CHashMap<usize, PortState>,
// TODO: Is this the correct implementation? I mean, there will be a really limited number of
// IRQs, if not just one, and since we probably wont use a thread pool scheduler like those of
// async-std or tokio, one could possibly assume that the futures themselves won't have to push
// all the wakers.
// TODO: This should probably be a BTreeMap (or just a VecMap) of states for each IRQ number,
// if more than one are used. I'm not sure if the XHCI interrupters actually use different
// IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts
// reapeatedly with some time in between), bulk, control, etc. I might be wrong though...
irq_state: Arc<IrqState>,
drivers: BTreeMap<usize, process::Child>,
drivers: CHashMap<usize, process::Child>,
scheme_name: String,
interrupt_method: InterruptMethod,
pcid_handle: Mutex<PcidServerHandle>,
irq_reactor: Mutex<Option<thread::JoinHandle<()>>>,
irq_reactor_sender: Sender<NewPendingTrb>,
// not used, but still stored so that the thread, when created, can get the channel without the
// channel being in a mutex.
irq_reactor_receiver: Receiver<NewPendingTrb>,
}
unsafe impl Send for Xhci {}
unsafe impl Sync for Xhci {}
struct PortState {
slot: u8,
input_context: Dma<InputContext>,
dev_desc: DevDesc,
cfg_idx: Option<u8>,
if_idx: Option<u8>,
input_context: Mutex<Dma<InputContext>>,
dev_desc: Option<DevDesc>,
endpoint_states: BTreeMap<u8, EndpointState>,
}
@@ -167,146 +232,209 @@ impl EndpointState {
}
impl Xhci {
pub fn new(scheme_name: String, address: usize) -> Result<Xhci> {
pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result<Xhci> {
let cap = unsafe { &mut *(address as *mut CapabilityRegs) };
println!(" - CAP {:X}", address);
debug!("CAP REGS BASE {:X}", address);
let page_size = {
let memory_fd = syscall::open("memory:", O_RDONLY)?;
let mut stat = syscall::data::StatVfs::default();
syscall::fstatvfs(memory_fd, &mut stat)?;
stat.f_bsize as usize
};
let op_base = address + cap.len.read() as usize;
let op = unsafe { &mut *(op_base as *mut OperationalRegs) };
println!(" - OP {:X}", op_base);
debug!("OP REGS BASE {:X}", op_base);
let (max_slots, max_ports) = {
println!(" - Wait for ready");
debug!("Waiting for xHC becoming ready.");
// Wait until controller is ready
while op.usb_sts.readf(1 << 11) {
println!(" - Waiting for XHCI ready");
trace!("Waiting for the xHC to be ready.");
}
println!(" - Stop");
debug!("Stopping the xHC");
// Set run/stop to 0
op.usb_cmd.writef(1, false);
println!(" - Wait for not running");
debug!("Waiting for the xHC to stop.");
// Wait until controller not running
while !op.usb_sts.readf(1) {
println!(" - Waiting for XHCI stopped");
trace!("Waiting for the xHC to stop.");
}
println!(" - Reset");
debug!("Resetting the xHC.");
op.usb_cmd.writef(1 << 1, true);
while op.usb_sts.readf(1 << 1) {
println!(" - Waiting for XHCI reset");
trace!("Waiting for the xHC to reset.");
}
println!(" - Read max slots");
debug!("Reading max slots.");
let max_slots = cap.max_slots();
let max_ports = cap.max_ports();
println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports);
info!("xHC max slots: {}, max ports: {}", max_slots, max_ports);
(max_slots, max_ports)
};
let port_base = op_base + 0x400;
let ports =
unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) };
println!(" - PORT {:X}", port_base);
debug!("PORT BASE {:X}", port_base);
let db_base = address + cap.db_offset.read() as usize;
let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) };
println!(" - DOORBELL {:X}", db_base);
debug!("DOORBELL REGS BASE {:X}", db_base);
let run_base = address + cap.rts_offset.read() as usize;
let run = unsafe { &mut *(run_base as *mut RuntimeRegs) };
println!(" - RUNTIME {:X}", run_base);
debug!("RUNTIME REGS BASE {:X}", run_base);
let mut xhci = Xhci {
// Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the
// DMA allocation (which is at least a 4k page).
let entries_per_page = page_size / mem::size_of::<Trb>();
let cmd = Ring::new(entries_per_page, true)?;
let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded();
let mut xhci = Self {
base: address as *const u8,
cap,
op,
ports,
dbs,
run,
dev_ctx: DeviceContextList::new(max_slots)?,
cmd: CommandRing::new()?,
handles: BTreeMap::new(),
next_handle: 0,
port_states: BTreeMap::new(),
irq_state: Arc::new(IrqState {
triggered: AtomicBool::new(false),
wakers: Mutex::new(Vec::new()),
}),
drivers: BTreeMap::new(),
cap,
page_size,
op: Mutex::new(op),
ports: Mutex::new(ports),
dbs: Mutex::new(dbs),
run: Mutex::new(run),
dev_ctx: DeviceContextList::new(max_slots)?,
scratchpad_buf_arr: None, // initialized in init()
cmd: Mutex::new(cmd),
primary_event_ring: Mutex::new(EventRing::new()?),
handles: CHashMap::new(),
next_handle: AtomicUsize::new(0),
port_states: CHashMap::new(),
drivers: CHashMap::new(),
scheme_name,
interrupt_method,
pcid_handle: Mutex::new(pcid_handle),
irq_reactor: Mutex::new(None),
irq_reactor_sender,
irq_reactor_receiver,
};
xhci.init(max_slots);
xhci.init(max_slots)?;
Ok(xhci)
}
pub fn init(&mut self, max_slots: u8) {
pub fn init(&mut self, max_slots: u8) -> Result<()> {
// Set enabled slots
println!(" - Set enabled slots to {}", max_slots);
self.op.config.write(max_slots as u32);
println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF);
debug!("Setting enabled slots to {}.", max_slots);
self.op.get_mut().unwrap().config.write(max_slots as u32);
debug!("Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF);
// Set device context address array pointer
let dcbaap = self.dev_ctx.dcbaap();
println!(" - Write DCBAAP: {:X}", dcbaap);
self.op.dcbaap.write(dcbaap as u64);
debug!("Writing DCBAAP: {:X}", dcbaap);
self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64);
// Set command ring control register
let crcr = self.cmd.crcr();
println!(" - Write CRCR: {:X}", crcr);
self.op.crcr.write(crcr as u64);
let crcr = self.cmd.get_mut().unwrap().register();
assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR");
debug!("Writing CRCR: {:X}", crcr);
self.op.get_mut().unwrap().crcr.write(crcr as u64);
// Set event ring segment table registers
println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize);
debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr());
{
let int = &mut self.run.get_mut().unwrap().ints[0];
let erstz = 1;
println!(" - Write ERSTZ: {}", erstz);
self.run.ints[0].erstsz.write(erstz);
debug!("Writing ERSTZ: {}", erstz);
int.erstsz.write(erstz);
let erdp = self.cmd.erdp();
println!(" - Write ERDP: {:X}", erdp);
self.run.ints[0].erdp.write(erdp as u64);
let erdp = self.primary_event_ring.get_mut().unwrap().erdp();
debug!("Writing ERDP: {:X}", erdp);
int.erdp.write(erdp as u64 | (1 << 3));
let erstba = self.cmd.erstba();
println!(" - Write ERSTBA: {:X}", erstba);
self.run.ints[0].erstba.write(erstba as u64);
let erstba = self.primary_event_ring.get_mut().unwrap().erstba();
debug!("Writing ERSTBA: {:X}", erstba);
int.erstba.write(erstba as u64);
debug!("Writing IMODC and IMODI: {} and {}", 0, 0);
int.imod.write(0);
debug!("Enabling Primary Interrupter.");
int.iman.writef(1 << 1 | 1, true);
println!(" - Enable interrupts");
self.run.ints[0].iman.writef(1 << 1, true);
}
self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true);
// Setup the scratchpad buffers that are required for the xHC to function.
self.setup_scratchpads()?;
// Set run/stop to 1
println!(" - Start");
self.op.usb_cmd.writef(1 | 1 << 2, true);
info!("Starting xHC.");
self.op.get_mut().unwrap().usb_cmd.writef(1, true);
// Wait until controller is running
println!(" - Wait for running");
while self.op.usb_sts.readf(1) {
println!(" - Waiting for XHCI running");
debug!("Waiting for start request to complete.");
while self.op.get_mut().unwrap().usb_sts.readf(1) {
trace!("Waiting for XHCI to report running status.");
}
// Ring command doorbell
println!(" - Ring doorbell");
self.dbs[0].write(0);
debug!("Ringing command doorbell.");
self.dbs.get_mut().unwrap()[0].write(0);
println!(" - XHCI initialized");
info!("XHCI initialized.");
if self.cap.cic() {
self.op.get_mut().unwrap().set_cie(true);
}
Ok(())
}
pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result<u8> {
pub fn setup_scratchpads(&mut self) -> Result<()> {
let buf_count = self.cap.max_scratchpad_bufs();
if buf_count == 0 {
return Ok(());
}
let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?;
self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64;
debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register());
self.scratchpad_buf_arr = Some(scratchpad_buf_arr);
Ok(())
}
pub async fn enable_port_slot(&self, slot_ty: u8) -> Result<u8> {
assert_eq!(slot_ty & 0x1F, slot_ty);
let cloned_event_trb =
self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
Ok(cloned_event_trb.event_slot())
let (event_trb, command_trb) =
self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await;
self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?;
self.event_handler_finished();
Ok(event_trb.event_slot())
}
pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> {
self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
pub async fn disable_port_slot(&self, slot: u8) -> Result<()> {
let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await;
self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?;
self.event_handler_finished();
Ok(())
}
@@ -314,49 +442,45 @@ impl Xhci {
self.dev_ctx.contexts[slot].slot.state()
}
pub fn probe(&mut self) -> Result<()> {
for i in 0..self.ports.len() {
pub async fn probe(&self) -> Result<()> {
info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::<Vec<_>>());
let port_count = { self.ports.lock().unwrap().len() };
for i in 0..port_count {
let (data, state, speed, flags) = {
let port = &self.ports[i];
let port = &self.ports.lock().unwrap()[i];
(port.read(), port.state(), port.speed(), port.flags())
};
println!(
" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
info!(
"XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}",
i, data, state, speed, flags
);
if flags.contains(port::PortFlags::PORT_CCS) {
//TODO: Link TRB when running to the end of the ring buffer
println!(" - Enable slot");
let slot_ty = self
.supported_protocol(i as u8)
.expect("Failed to find supported protocol information for port")
.proto_slot_ty();
let slot = self.enable_port_slot(slot_ty)?;
println!(" - Slot {}", slot);
debug!("Slot type: {}", slot_ty);
debug!("Enabling slot.");
let slot = self.enable_port_slot(slot_ty).await?;
info!("Enabled port {}, which the xHC mapped to {}", i, slot);
let mut input = Dma::<InputContext>::zeroed()?;
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?;
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?;
info!("Addressed device");
let dev_desc = Self::get_dev_desc_raw(
&mut self.ports,
&mut self.run,
&mut self.cmd,
&mut self.dbs,
i,
slot,
&mut ring,
)?;
self.update_default_control_pipe(&mut input, slot, &dev_desc)?;
// TODO: Should the descriptors be cached in PortState, or refetched?
let mut port_state = PortState {
slot,
input_context: input,
dev_desc,
input_context: Mutex::new(input),
dev_desc: None,
cfg_idx: None,
if_idx: None,
endpoint_states: std::iter::once((
0,
EndpointState {
@@ -366,25 +490,33 @@ impl Xhci {
))
.collect::<BTreeMap<_, _>>(),
};
self.port_states.insert(i, port_state);
if self.cap.cic() {
self.op.set_cie(true);
let dev_desc = self.get_desc(i, slot).await?;
self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc);
{
let mut port_state = self.port_states.get_mut(&i).unwrap();
let mut input = port_state.input_context.lock().unwrap();
let dev_desc = port_state.dev_desc.as_ref().unwrap();
self.update_default_control_pipe(&mut *input, slot, dev_desc).await?;
}
/*match self.spawn_drivers(i, &mut port_state) {
Ok(()) => (),
Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err),
Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err),
}*/
self.port_states.insert(i, port_state);
}
}
Ok(())
}
pub fn update_default_control_pipe(
&mut self,
pub async fn update_default_control_pipe(
&self,
input_context: &mut Dma<InputContext>,
slot_id: u8,
dev_desc: &DevDesc,
@@ -403,14 +535,18 @@ impl Xhci {
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
self.execute_command("EVALUATE_CONTEXT", |trb, cycle| {
let (event_trb, command_trb) = self.execute_command(|trb, cycle| {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
})?;
}).await;
self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?;
self.event_handler_finished();
Ok(())
}
pub fn address_device(
&mut self,
pub async fn address_device(
&self,
input_context: &mut Dma<InputContext>,
i: usize,
slot_ty: u8,
@@ -498,39 +634,65 @@ impl Xhci {
let input_context_physical = input_context.physical();
self.execute_command("ADDRESS_DEVICE", |trb, cycle| {
let (event_trb, _) = self.execute_command(|trb, cycle| {
trb.address_device(slot, input_context_physical, false, cycle)
})
.expect("ADDRESS_DEVICE failed");
}).await;
if event_trb.completion_code() != TrbCompletionCode::Success as u8 {
error!("Failed to address device at slot {} (port {})", slot, i);
self.event_handler_finished();
return Err(Error::new(EIO));
}
self.event_handler_finished();
Ok(ring)
}
pub fn uses_msi(&self) -> bool {
if let InterruptMethod::Msi = self.interrupt_method { true } else { false }
}
pub fn uses_msix(&self) -> bool {
if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false }
}
// TODO: Perhaps use an rwlock?
pub fn msix_info(&self) -> Option<MutexGuard<'_, MsixInfo>> {
match self.interrupt_method {
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
_ => None,
}
}
pub fn msix_info_mut(&self) -> Option<MutexGuard<'_, MsixInfo>> {
match self.interrupt_method {
InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()),
_ => None,
}
}
pub fn trigger_irq(&mut self) -> bool {
// Read the Interrupter Pending bit.
if self.run.ints[0].iman.readf(1) {
//println!("XHCI Interrupt");
/// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always
/// true when using MSI/MSI-X.
pub fn received_irq(&self) -> bool {
let mut runtime_regs = self.run.lock().unwrap();
// If set, set it back to zero, so that new interrupts can be triggered.
// FIXME: MSI and MSI-X systems
self.run.ints[0].iman.writef(1, true);
// Wake all futures awaiting the IRQ.
for waker in self.irq_state.wakers.lock().unwrap().drain(..) {
waker.wake();
}
if self.uses_msi() || self.uses_msix() {
// Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit
// doesn't have to be touched.
trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3));
true
} else if runtime_regs.ints[0].iman.readf(1) {
trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3));
// If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is
// a special register to specify whether the IRQ actually came from the xHC.
runtime_regs.ints[0].iman.writef(1, true);
// The interrupt came from the xHC.
true
} else {
// The interrupt came from a different device.
false
}
}
pub(crate) fn irq(&self) -> IrqFuture {
IrqFuture {
state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)),
}
}
fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> {
fn spawn_drivers(&self, port: usize, ps: &mut PortState) -> Result<()> {
// TODO: There should probably be a way to select alternate interfaces, and not just the
// first one.
// TODO: Now that there are some good error crates, I don't think errno.h error codes are
@@ -538,12 +700,14 @@ impl Xhci {
let ifdesc = &ps
.dev_desc
.as_ref().unwrap()
.config_descs
.first()
.ok_or(Error::new(EBADF))?
.interface_descs
.first()
.ok_or(Error::new(EBADF))?;
let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG;
if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| {
@@ -553,7 +717,7 @@ impl Xhci {
.map(|subclass| subclass == ifdesc.sub_class)
.unwrap_or(true)
}) {
println!("Loading driver \"{}\"", driver.name);
info!("Loading subdriver\"{}\"", driver.name);
let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?;
let if_proto = ifdesc.protocol;
@@ -680,6 +844,18 @@ impl Xhci {
.find(|speed| speed.psiv() == psiv)
}
}
pub fn start_irq_reactor(hci: &Arc<Xhci>, irq_file: Option<File>) {
let receiver = hci.irq_reactor_receiver.clone();
let hci_clone = Arc::clone(&hci);
debug!("About to start IRQ reactor");
*hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || {
info!("Started IRQ reactor thread");
IrqReactor::new(hci_clone, receiver, irq_file).run()
}));
}
#[derive(Deserialize)]
struct DriverConfig {
name: String,
@@ -707,44 +883,3 @@ lazy_static! {
toml::from_slice::<DriversConfig>(TOML).expect("Failed to parse internally embedded config file")
};
}
pub(crate) struct IrqFuture {
state: IrqFutureState,
}
struct IrqState {
triggered: AtomicBool,
// TODO: Perhaps a channel?
wakers: Mutex<Vec<task::Waker>>,
}
enum IrqFutureState {
Pending(Weak<IrqState>),
Finished,
}
impl std::future::Future for IrqFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
let this = self.get_mut();
match &mut this.state {
// TODO: Ordering?
IrqFutureState::Pending(state_weak) => {
let state = state_weak.upgrade().expect(
"IRQ futures keep getting polled even after the driver has been deinitialized",
);
if state.triggered.load(atomic::Ordering::SeqCst) {
this.state = IrqFutureState::Finished;
task::Poll::Ready(())
} else {
state.wakers.lock().unwrap().push(context.waker().clone());
task::Poll::Pending
}
}
IrqFutureState::Finished => panic!("polling finished future"),
}
}
}
+56 -1
View File
@@ -1,3 +1,5 @@
use std::mem;
use syscall::error::Result;
use syscall::io::Dma;
@@ -26,7 +28,7 @@ impl Ring {
addr as u64 | self.cycle as u64
}
pub fn next(&mut self) -> (&mut Trb, bool) {
pub fn next_index(&mut self) -> usize {
let mut i;
loop {
i = self.i;
@@ -45,7 +47,11 @@ impl Ring {
break;
}
}
i
}
pub fn next(&mut self) -> (&mut Trb, bool) {
let i = self.next_index();
(&mut self.trbs[i], self.cycle)
}
/// Endless iterator that iterates through the ring items, over and over again. The iterator
@@ -53,6 +59,55 @@ impl Ring {
pub fn iter(&self) -> impl Iterator<Item = &Trb> + '_ {
Iter { ring: self, i: self.i }
}
/// Takes a physical address and returns the index into this ring, that the index represents.
/// Returns `None` if the address is outside the bounds of this ring.
///
/// # Panics
/// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB.
// TODO: Use usize instead of u64.
pub fn phys_addr_to_index(&self, paddr: u64) -> Option<usize> {
let base = self.trbs.physical();
let offset = paddr.checked_sub(base as u64)? as usize;
assert_eq!(offset % mem::size_of::<Trb>(), 0, "unaligned TRB physical address");
let index = offset / mem::size_of::<Trb>();
if index > self.trbs.len() {
return None;
}
Some(index)
}
pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> {
Some(&self.trbs[self.phys_addr_to_index(paddr)?])
}
pub fn phys_addr_to_entry_mut(&mut self, paddr: u64) -> Option<&mut Trb> {
let index = self.phys_addr_to_index(paddr)?;
Some(&mut self.trbs[index])
}
pub fn phys_addr_to_entry(&self, paddr: u64) -> Option<Trb> {
Some(self.trbs[self.phys_addr_to_index(paddr)?].clone())
}
pub(crate) fn start_virt_addr(&self) -> *const Trb {
self.trbs.as_ptr()
}
pub(crate) fn end_virt_addr(&self) -> *const Trb {
unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) }
}
pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 {
let trb_virt_pointer = trb as *const Trb;
let trbs_base_virt_pointer = self.trbs.as_ptr();
if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::<Trb>() {
panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb);
}
let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64;
let trbs_base_phys_ptr = self.trbs.physical() as u64;
let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base;
trb_phys_ptr
}
/*
/// Endless mutable iterator that iterates through the ring items, over and over again. The
/// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed.
+606 -535
View File
File diff suppressed because it is too large Load Diff
+84 -6
View File
@@ -5,6 +5,7 @@ use syscall::io::{Io, Mmio};
use super::context::StreamContextType;
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TrbType {
Reserved,
/* Transfer */
@@ -33,8 +34,8 @@ pub enum TrbType {
ForceHeader,
NoOpCmd,
/* Reserved */
Rsv24,
Rsv25,
GetExtendedProperty,
SetExtendedProperty,
Rsv26,
Rsv27,
Rsv28,
@@ -54,6 +55,7 @@ pub enum TrbType {
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TrbCompletionCode {
Invalid,
Success,
@@ -157,6 +159,34 @@ impl Trb {
pub fn completion_param(&self) -> u32 {
self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK
}
fn has_completion_trb_pointer(&self) -> bool {
if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 || self.completion_code() == TrbCompletionCode::RingOverrun as u8 {
false
} else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 {
false
} else {
true
}
}
pub fn completion_trb_pointer(&self) -> Option<u64> {
debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8);
if self.has_completion_trb_pointer() {
Some(self.data.read())
} else {
None
}
}
pub fn transfer_event_trb_pointer(&self) -> Option<u64> {
debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8);
if self.has_completion_trb_pointer() {
Some(self.data.read())
} else {
None
}
}
pub fn event_slot(&self) -> u8 {
(self.control.read() >> 24) as u8
}
@@ -203,6 +233,15 @@ impl Trb {
| (cycle as u32),
);
}
pub fn disable_slot(&mut self, slot: u8, cycle: bool) {
self.set(
0,
0,
(u32::from(slot) << 24)
| ((TrbType::DisableSlot as u32) << 10)
| u32::from(cycle)
);
}
pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) {
assert_eq!(
@@ -335,13 +374,15 @@ impl Trb {
);
}
pub fn status(&mut self, input: bool, cycle: bool) {
pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) {
self.set(
0,
0,
((input as u32) << 16)
u32::from(interrupter) << 22,
(u32::from(input) << 16)
| ((TrbType::StatusStage as u32) << 10)
| (1 << 5)
| (u32::from(ioc) << 5)
| (u32::from(ch) << 4)
| (u32::from(ent) << 1)
| (cycle as u32),
);
}
@@ -374,6 +415,43 @@ impl Trb {
| ((TrbType::Normal as u32) << 10),
)
}
pub fn is_command_trb(&self) -> bool {
let valid_trb_types = [
TrbType::NoOpCmd as u8,
TrbType::EnableSlot as u8,
TrbType::DisableSlot as u8,
TrbType::AddressDevice as u8,
TrbType::ConfigureEndpoint as u8,
TrbType::EvaluateContext as u8,
TrbType::ResetEndpoint as u8,
TrbType::StopEndpoint as u8,
TrbType::SetTrDequeuePointer as u8,
TrbType::ResetDevice as u8,
TrbType::ForceEvent as u8,
TrbType::NegotiateBandwidth as u8,
TrbType::SetLatencyToleranceValue as u8,
TrbType::GetPortBandwidth as u8,
TrbType::ForceHeader as u8,
TrbType::GetExtendedProperty as u8,
TrbType::SetExtendedProperty as u8,
];
valid_trb_types.contains(&self.trb_type())
}
pub fn is_transfer_trb(&self) -> bool {
// XXX: Unfortunately, the only way to use match statements with integer constants, is to
// precast them into valid enum values, which either requires a derive macro such as
// num_traits's #[derive(FromPrimitive)], or manually writing the reverse match statement
// first.
let valid_trb_types = [
TrbType::Normal as u8,
TrbType::SetupStage as u8,
TrbType::DataStage as u8,
TrbType::StatusStage as u8,
TrbType::Isoch as u8,
TrbType::NoOp as u8,
];
valid_trb_types.contains(&self.trb_type())
}
}
impl fmt::Debug for Trb {